@peter.naydenov/shortcuts 3.3.1 → 3.4.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.
@@ -0,0 +1,320 @@
1
+ import { beforeEach, afterEach, describe, it, expect } from 'vitest'
2
+ import { userEvent } from '@vitest/browser/context'
3
+ import {
4
+ getByLabelText,
5
+ getByText,
6
+ getByTestId,
7
+ queryByTestId,
8
+ // Tip: all queries are also exposed on an object
9
+ // called "queries" which you could import here as well
10
+ waitFor
11
+ } from '@testing-library/dom'
12
+
13
+
14
+
15
+ import '../test-helpers/style.css'
16
+ import Block from '../test-helpers/Block.jsx'
17
+ import VisaulController from '@peter.naydenov/visual-controller-for-react'
18
+ import wait from '../test-helpers/wait.js'
19
+ import {
20
+ shortcuts
21
+ , pluginKey
22
+ , pluginClick
23
+ , pluginForm
24
+ } from '../src/main.js'
25
+
26
+
27
+
28
+ const html = new VisaulController ();
29
+ let
30
+ a = false
31
+ , b = false
32
+ , c = null
33
+ ;
34
+
35
+ const contextDefinition = {
36
+ general : {
37
+ ' key : shift+a': [
38
+ () => a = true,
39
+ () => c = 'triggered'
40
+ ]
41
+ }
42
+ , touch : {
43
+ // Single click with left button
44
+ ' click: left-1': ({ target }) => {
45
+ b = true
46
+ // Named argument 'target' should be available
47
+ c = target.dataset.click
48
+ },
49
+ // Double click with left button
50
+ 'click: left-2': ({ target }) => {
51
+ b = true
52
+ c = target.dataset.click
53
+ },
54
+ // Single click with right button
55
+ 'click: right-1': () => c = 'right'
56
+ }
57
+ , extra : {
58
+ 'key : p,r,o,b,a': () => b = true
59
+ }
60
+ , extend : {
61
+ 'form : watch' : () => 'input'
62
+ , 'form : define' : () => 'input'
63
+ , 'form : action' : () => [
64
+ {
65
+ fn : (e) => console.log ( e.target )
66
+ , type : 'input'
67
+ , mode : 'in'
68
+ }
69
+ ]
70
+ }
71
+ }
72
+
73
+
74
+ let short = shortcuts ();
75
+
76
+
77
+
78
+ describe ( 'Click plugin', () => {
79
+
80
+
81
+
82
+ beforeEach ( async () => {
83
+ short.load ( contextDefinition )
84
+ let container = document.createElement ( 'div' );
85
+ container.id = 'app'
86
+ document.body.appendChild ( container )
87
+ await html.publish ( Block, {}, 'app' )
88
+ a = false, b = false
89
+ }) // beforeEach
90
+
91
+
92
+
93
+ afterEach ( async () => {
94
+ short.reset ();
95
+ a = false, b = false, c = null;
96
+ }) // afterEach
97
+
98
+
99
+
100
+ it ( 'No "click" plugin installed', async () => {
101
+ let r = short.listShortcuts ('touch');
102
+ // Shortcuts are untouched if plugin is not installed
103
+ expect ( r[0]).to.equal ( ' click: left-1' )
104
+ }) // it no 'click' plugin installed
105
+
106
+
107
+
108
+ it ( 'Click plugin installed', async () => {
109
+ short.enablePlugin ( pluginClick )
110
+ let r = short.listShortcuts ( 'touch' );
111
+ // Shortcuts are normalized
112
+ expect ( r[0]).to.equal ( 'CLICK:LEFT-1' )
113
+ }) // it click plugin installed
114
+
115
+
116
+
117
+ it ( 'Single left click', async () => {
118
+ expect ( b ).to.equal ( false )
119
+ short.enablePlugin ( pluginClick )
120
+ short.changeContext ( 'touch' )
121
+ await userEvent.click ( document.querySelector ( '#rspan' ) )
122
+ await wait ( 330 )
123
+ await waitFor ( () => {
124
+ expect ( b ).to.equal ( true )
125
+ // Target is a element that contains data-click property!
126
+ expect ( c ).to.equal ( 'red' )
127
+ // We clicked on span, but target is the parent element
128
+ // that contains data-click property
129
+ }, { timeout: 1000, interval: 12 })
130
+ }) // it single left click
131
+
132
+
133
+
134
+ it ( 'Double left click', async () => {
135
+ expect ( b ).to.equal ( false )
136
+ short.enablePlugin ( pluginClick )
137
+ short.changeContext ( 'touch' )
138
+ await userEvent.dblClick ( document.querySelector ( '#rspan' ) )
139
+ await wait ( 20 )
140
+ // Default wait mouse timeout is 320 ms, but maxClicks is set to 2,
141
+ // so we don't need to wait for timeout
142
+ await waitFor ( () => {
143
+ expect ( b ).to.equal ( true )
144
+ // Target is a element that contains data-click property!
145
+ expect ( c ).to.equal ( 'red' )
146
+ // We clicked on span, but target is the parent element
147
+ // that contains data-click property
148
+ }, { timeout: 1000, interval: 12 })
149
+ }) // it double left click
150
+
151
+
152
+
153
+ it ( 'Triple left click', async () => {
154
+ short.enablePlugin ( pluginClick )
155
+ const hitItem = document.querySelector ( '#rspan' );
156
+ expect ( a ).to.equal ( false )
157
+ short.changeContext ( 'touch' )
158
+ // Load will restart the selected context
159
+ short.load ({
160
+ // load will overwrite existing 'touch' context definition
161
+ 'touch' : {
162
+ 'click: left-3' : () => a = true
163
+ }
164
+ })
165
+ await wait ( 12 )
166
+ await userEvent.tripleClick ( hitItem )
167
+ // Default wait mouse timeout is 320 ms, but maxClicks is set to 3,
168
+ // so we don't need to wait for timeout
169
+ await waitFor ( () => {
170
+ expect ( a ).to.equal ( true )
171
+ expect ( b ).to.equal ( false )
172
+ }, { timeout: 1000, interval: 12 })
173
+ }) // it triple left click
174
+
175
+
176
+
177
+ it ( 'Single right click', async () => {
178
+ short.enablePlugin ( pluginClick )
179
+ // Context 'touch' was changed during previous test
180
+ // Return to original context.
181
+ short.load ( contextDefinition )
182
+ short.changeContext ( 'touch' )
183
+ let find = null
184
+ await waitFor ( () => {
185
+ find = document.querySelector ( '#rspan' )
186
+ },{ timeout: 1000, interval: 12 })
187
+ if ( find ) await userEvent.click ( find , { button:'right' })
188
+ // Default wait mouse timeout is 320 ms
189
+ await wait ( 320 )
190
+ await waitFor ( () => {
191
+ expect ( c ).to.equal ( 'right' )
192
+ }, { timeout: 1000, interval: 12 })
193
+ }) // it single right click
194
+
195
+
196
+
197
+ it ( 'Arguments of click handler', async () => {
198
+ /**
199
+ * Need to know arguments for 'click' handler
200
+ * function myMouseHandler ({
201
+ * context // (string) Name of the current context;
202
+ * , note // (string) Name of the note or null if note isn't set;
203
+ * , dependencies // (object) Object with dependencies that you have set by calling `setDependencies` method;
204
+ * , target // (DOM element). Target element of the mouse event;
205
+ * , targetProps // (object). Coordinates of the target element (top, left, right, bottom, width, height) or null if target element is not available;
206
+ * , x // (number). X coordinate of the target element;
207
+ * , y // (number). Y coordinate of the target element;
208
+ * , event // (object). Original mouse event object;
209
+ * }) {
210
+ * // Body of the handler. Do something...
211
+ * }
212
+ */
213
+ // Ensure clean state for this test
214
+ let megaBtn = document.querySelector ( '[data-click="mega"]' )
215
+ let test = [];
216
+ let i = 0;
217
+ short.enablePlugin ( pluginClick )
218
+ short.setDependencies ({ test })
219
+ short.load ({
220
+ 'local' : {
221
+ 'click: left-1' : ({
222
+ dependencies
223
+ , target
224
+ , x
225
+ , y
226
+ , targetProps
227
+ , context
228
+ }) => {
229
+ const
230
+ { test } = dependencies
231
+ , result = {
232
+ x
233
+ , y
234
+ , targetProps
235
+ , context
236
+ }
237
+ ;
238
+ result.target = target.dataset.click
239
+ test.push ( result )
240
+ i++
241
+ }
242
+ } // local
243
+ })
244
+ short.changeContext ( 'local' )
245
+ expect ( megaBtn ).to.not.be.null
246
+ await userEvent.click ( megaBtn )
247
+ await wait ( 50 ) // Wait for click processing
248
+ await waitFor ( () => {
249
+ expect ( i ).to.be.equal ( 1 )
250
+ let result = test[0];
251
+ expect ( result.target ).to.be.equal ( 'mega' )
252
+ expect ( result.context ).to.be.equal ( 'local' )
253
+ }, { timeout: 1000, interval: 12 })
254
+ }) // it arguments of click handler
255
+
256
+
257
+
258
+ it ( 'Click on anchor', async () => {
259
+ // Click on anchor that don't have click-data attribute.
260
+ let result = 'none';
261
+ short.enablePlugin ( pluginClick )
262
+ short.load ({ 'extra' : {
263
+ 'click: 1 - left' : ({target, context, event }) => { // Order of button name and number of click is not important
264
+ event.preventDefault ()
265
+ expect ( context ).to.be.equal ( 'extra' )
266
+ expect ( target.nodeName ).to.be.equal ( 'A' )
267
+ result = target.nodeName
268
+ }
269
+ }
270
+ })
271
+ short.changeContext ( 'extra' )
272
+ let loc = document.querySelector ( '#anchor' ) || false;
273
+ if ( loc ) await userEvent.click ( loc )
274
+ expect ( result ).to.be.equal ( 'A' )
275
+ }) // it click on anchor
276
+
277
+
278
+
279
+ it ( 'Mute click plugin', async () => {
280
+ const
281
+ result = []
282
+ , trg = document.querySelector ( '#rspan' )
283
+ ;
284
+
285
+ let i = 0;
286
+ result.push ( 'init' )
287
+
288
+
289
+ short.load ({
290
+ 'local' : {
291
+ 'click: left-1 ' : ({dependencies}) => {
292
+ let { result } = dependencies;
293
+ result.push ( i++ )
294
+ }
295
+ }
296
+ })
297
+ short.setDependencies ({ result })
298
+ short.enablePlugin ( pluginClick )
299
+ short.changeContext ( 'local' )
300
+
301
+
302
+ await userEvent.click ( trg )
303
+ await wait( 330 )
304
+ await waitFor ( () => {
305
+ // We checking if the shortcut works
306
+ expect ( result ).to.have.lengthOf ( 2 )
307
+ expect ( i ).to.equal ( 1 )
308
+ }, { timeout: 1000, interval: 12 })
309
+
310
+ short.mutePlugin ( 'click' )
311
+
312
+ await userEvent.click ( trg )
313
+ await waitFor ( () => {
314
+ // Plugin is muted, so we don't expect any changes
315
+ expect ( result ).to.have.lengthOf ( 2 )
316
+ expect ( i ).to.equal ( 1 )
317
+ }, { timeout: 1000, interval: 12 })
318
+ }) // it mute click plugin
319
+
320
+ }) // describe
@@ -0,0 +1,90 @@
1
+ import { beforeEach, afterEach, describe, it, test, expect } from 'vitest'
2
+ import { userEvent } from '@vitest/browser/context'
3
+ import {
4
+ getByLabelText,
5
+ getByText,
6
+ getByTestId,
7
+ queryByTestId,
8
+ // Tip: all queries are also exposed on an object
9
+ // called "queries" which you could import here as well
10
+ waitFor
11
+ } from '@testing-library/dom'
12
+
13
+
14
+
15
+ import '../test-helpers/style.css'
16
+ import Block from '../test-helpers/Block.jsx'
17
+ import VisaulController from '@peter.naydenov/visual-controller-for-react'
18
+ import wait from '../test-helpers/wait.js'
19
+ import {
20
+ shortcuts
21
+ , pluginClick
22
+ , pluginKey
23
+ , pluginForm
24
+ } from '../src/main.js'
25
+
26
+
27
+
28
+ const html = new VisaulController ();
29
+ let
30
+ a = false
31
+ , b = false
32
+ , c = null
33
+ ;
34
+
35
+ const contextDefinition = {
36
+ general : {
37
+ ' key : shift+a': [
38
+ () => a = true,
39
+ () => c = 'triggered'
40
+ ]
41
+ }
42
+ , touch : {
43
+ // Single click with left button
44
+ 'click: left-1': () => b = true,
45
+ // Double click with left button
46
+ 'click: left-2': () => b = true,
47
+ // Single click with right button
48
+ 'click: right-1': () => b = true
49
+ }
50
+ , extra : {
51
+ 'key : p,r,o,b,a': () => b = true
52
+ }
53
+ , extend : {
54
+ 'form : watch' : () => 'input'
55
+ , 'form : define' : () => 'input'
56
+ , 'form : action' : () => [
57
+ {
58
+ fn : (e) => console.log ( e.target )
59
+ , type : 'input'
60
+ , mode : 'in'
61
+ }
62
+ ]
63
+ }
64
+ }
65
+
66
+ let short = shortcuts ();
67
+
68
+
69
+
70
+ describe.skip ( 'Form plugin', () => {
71
+
72
+ beforeEach ( async () => {
73
+ short.load ( contextDefinition )
74
+ let container = document.createElement ( 'div' )
75
+ container.id = 'app'
76
+ document.body.appendChild ( container )
77
+ await html.publish ( Block, {}, 'app' )
78
+ a = false, b = false
79
+ }) // beforeEach
80
+
81
+
82
+
83
+ afterEach ( async () => {
84
+ short.reset ()
85
+ a = false, b = false, c = null;
86
+ }) // afterEach
87
+
88
+
89
+
90
+ }) // describe
@@ -0,0 +1,18 @@
1
+ async function setup () {
2
+ let st = document.createElement ( 'style' )
3
+ st.textContent = cssCode
4
+ document.head.appendChild ( st )
5
+ await waitFor ( () => {
6
+ expect ( document.head ).to.have.property ( 'style' )
7
+ })
8
+
9
+
10
+ let container = document.createElement ( 'div' )
11
+ container.id = 'app'
12
+ document.body.appendChild ( container )
13
+ html.publish ( Block, {}, 'app' )
14
+ a = false, b = false
15
+ } // setup func.
16
+
17
+
18
+ export default setup
@@ -0,0 +1,8 @@
1
+ function wait (ms) {
2
+ return new Promise((resolve) => setTimeout(resolve, ms));
3
+ }
4
+
5
+
6
+ export default wait
7
+
8
+
@@ -0,0 +1,21 @@
1
+ import { defineConfig } from 'vitest/config'
2
+ import react from '@vitejs/plugin-react'
3
+
4
+ export default defineConfig ({
5
+ plugins: [react()],
6
+ test: {
7
+ coverage: {
8
+ reporter: ['lcov', 'text-summary']
9
+ },
10
+ browser: {
11
+ enabled: true,
12
+ headless: true,
13
+ provider: 'playwright',
14
+ instances: [
15
+ {
16
+ browser: 'chromium'
17
+ }
18
+ ]
19
+ }
20
+ }
21
+ })
@@ -1,9 +0,0 @@
1
- export default function HelloWorld({ name }) {
2
- const parent = document.createElement('div')
3
-
4
- const h1 = document.createElement('h1')
5
- h1.textContent = 'Hello ' + name + '!'
6
- parent.appendChild(h1)
7
-
8
- return parent
9
- }
@@ -1,11 +0,0 @@
1
- import { expect, test } from 'vitest'
2
- import { getByText } from '@testing-library/dom'
3
- import HelloWorld from './HelloWorld.js'
4
-
5
- test('renders name', () => {
6
- const parent = HelloWorld({ name: 'Vitest' })
7
- document.body.appendChild(parent)
8
-
9
- const element = getByText(parent, 'Hello Vitest!')
10
- expect(element).toBeInTheDocument()
11
- })
@@ -1,19 +0,0 @@
1
- import { defineWorkspace } from 'vitest/config'
2
-
3
- export default defineWorkspace([
4
- // If you want to keep running your existing tests in Node.js, uncomment the next line.
5
- // 'vite.config.js',
6
- {
7
- extends: 'vite.config.js',
8
- test: {
9
- environment: 'browser',
10
- browser: {
11
- enabled: true,
12
- name: 'chromium',
13
- provider: 'playwright',
14
- // https://vitest.dev/guide/browser/playwright
15
- configs: [],
16
- },
17
- },
18
- },
19
- ])
File without changes
File without changes