@peter.naydenov/shortcuts 3.1.3 → 3.2.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.
- package/Changelog.md +7 -0
- package/README.md +64 -2
- package/dist/shortcuts.cjs +1 -1
- package/dist/shortcuts.esm.mjs +1 -1
- package/dist/shortcuts.umd.js +1 -1
- package/index.html +68 -16
- package/package.json +14 -12
- package/src/main.js +7 -4
- package/src/methods/changeContext.js +3 -1
- package/src/plugins/form/_defaults.js +18 -0
- package/src/plugins/form/_listenDOM.js +90 -0
- package/src/plugins/form/_normalizeShortcutName.js +21 -0
- package/src/plugins/form/_registerShortcutEvents.js +71 -0
- package/src/plugins/form/index.js +84 -0
- package/src/plugins/key/_listenDOM.js +1 -1
- package/test/01-general.test.js +299 -0
- package/test-components/Block.jsx +2 -0
- package/vitest-example/HelloWorld.js +9 -0
- package/vitest-example/HelloWorld.test.js +11 -0
- package/vitest.workspace.js +19 -0
- package/cypress/fixtures/example.json +0 -5
- package/cypress/support/commands.js +0 -25
- package/cypress/support/component-index.html +0 -14
- package/cypress/support/component.js +0 -27
- package/cypress/support/e2e.js +0 -20
- package/cypress.config.js +0 -10
- package/test/01-general.cy.js +0 -246
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
function _registerShortcutEvents ( dependencies, pluginState ) {
|
|
4
|
+
const
|
|
5
|
+
{ regex, _defaults, ev } = dependencies
|
|
6
|
+
, {
|
|
7
|
+
currentContext : { name: contextName }
|
|
8
|
+
, shortcuts
|
|
9
|
+
, callbacks
|
|
10
|
+
} = pluginState
|
|
11
|
+
;
|
|
12
|
+
let watch=[], define=[], action=[];
|
|
13
|
+
if ( contextName == null ) return false
|
|
14
|
+
Object.entries ( shortcuts[contextName] ).forEach ( ([shortcutName, list ]) => {
|
|
15
|
+
let isFormEv = regex.test ( shortcutName );
|
|
16
|
+
if ( !isFormEv ) return
|
|
17
|
+
if ( shortcutName === 'FORM:WATCH' ) watch = list
|
|
18
|
+
if ( shortcutName === 'FORM:DEFINE' ) define = list
|
|
19
|
+
if ( shortcutName === 'FORM:ACTION' ) action = list
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
if ( action.length === 0 ) return false
|
|
23
|
+
|
|
24
|
+
let setTypes = new Set ();
|
|
25
|
+
if ( define.length === 0 ) define = [ _defaults.define ]
|
|
26
|
+
if ( watch.length === 0 ) watch = [ _defaults.watch ]
|
|
27
|
+
let watchList = watch.map ( el => el() )
|
|
28
|
+
.reduce ( ( res, el) => {
|
|
29
|
+
res.push ( el )
|
|
30
|
+
return res
|
|
31
|
+
}, [])
|
|
32
|
+
pluginState.watchList = document.querySelectorAll ( watchList )
|
|
33
|
+
pluginState.watchList.forEach ( el => setTypes.add (define[0](el)) )
|
|
34
|
+
|
|
35
|
+
pluginState.typeFn = define[0] ? define[0] : _defaults.define
|
|
36
|
+
action.forEach ( act => {
|
|
37
|
+
|
|
38
|
+
if ( !(act instanceof Function)) {
|
|
39
|
+
console.warn ( `Warning: The 'form:action' should be a function.` )
|
|
40
|
+
return false
|
|
41
|
+
}
|
|
42
|
+
let list = act ()
|
|
43
|
+
if ( !(list instanceof Array) ) {
|
|
44
|
+
console.warn ( `Warning: The 'form:action' function should RETURN an array.` )
|
|
45
|
+
return false
|
|
46
|
+
}
|
|
47
|
+
act().forEach ( ({fn, type, timing, wait=0 }) => {
|
|
48
|
+
if ( setTypes.has ( type) && fn instanceof Function ) {
|
|
49
|
+
let key = `${type}/${timing}`
|
|
50
|
+
const hasProperty = callbacks.hasOwnProperty ( key );
|
|
51
|
+
hasProperty ?
|
|
52
|
+
callbacks[key].push ( fn ) :
|
|
53
|
+
callbacks[key] = [ fn ]
|
|
54
|
+
if ( !hasProperty ) {
|
|
55
|
+
ev.on ( key, ( props, callbacks ) => { // Register the 'type/timing' as an event
|
|
56
|
+
callbacks.forEach ( cb => { if ( cb instanceof Function ) cb ( props ) })
|
|
57
|
+
})
|
|
58
|
+
}
|
|
59
|
+
} // if function
|
|
60
|
+
if ( timing === 'instant' ) pluginState.wait[`${type}`] = wait
|
|
61
|
+
}) // for each act
|
|
62
|
+
}) // for each action
|
|
63
|
+
if ( Object.keys(pluginState.callbacks).length > 0 ) return true
|
|
64
|
+
else return false
|
|
65
|
+
} // _registerShortcutEvents func.
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
export default _registerShortcutEvents
|
|
70
|
+
|
|
71
|
+
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
// import all plugin files here
|
|
4
|
+
import _listenDOM from './_listenDOM.js'
|
|
5
|
+
import _normalizeShortcutName from './_normalizeShortcutName.js'
|
|
6
|
+
import _registerShortcutEvents from './_registerShortcutEvents.js'
|
|
7
|
+
import _defaults from './_defaults.js'
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
function pluginForm ( dependencies, state, options ) {
|
|
12
|
+
/**
|
|
13
|
+
* 'form: watch' - A function. Should return a string. Define a selection that will be watched for changes. example: 'input, select.color, textarea, #name'
|
|
14
|
+
* 'form: define' - A function that receives every watched element. Should return text value that represents the type of the
|
|
15
|
+
* element according custom specification. Types could be specific for every single form.
|
|
16
|
+
* 'form:action' - List of Callback objects.
|
|
17
|
+
* Callback definition object:
|
|
18
|
+
* {
|
|
19
|
+
* fn: function to be called
|
|
20
|
+
* type: fn should be executed on type of the element
|
|
21
|
+
* timing: 'in' | 'out' | 'instant' - when to execute the function
|
|
22
|
+
* wait: time in milliseconds to wait before executing the function again. Works only with mode 'instant'.
|
|
23
|
+
* }
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
let
|
|
27
|
+
{ currentContext, shortcuts } = state
|
|
28
|
+
, { inAPI } = dependencies
|
|
29
|
+
, deps = {
|
|
30
|
+
ev: dependencies.ev
|
|
31
|
+
, mainDependencies : dependencies
|
|
32
|
+
, regex : /FORM\s*\:/i
|
|
33
|
+
, _defaults
|
|
34
|
+
}
|
|
35
|
+
, pluginState = {
|
|
36
|
+
currentContext
|
|
37
|
+
, shortcuts
|
|
38
|
+
, callbacks : {} // Functions callbacks arranged by 'type/timing' : [ callback, ...otherCallbacks ]
|
|
39
|
+
, typeFn : '' // Type definition function
|
|
40
|
+
, watchList : [] // list of watched elements
|
|
41
|
+
, wait : {} // wait time for 'instant' mode
|
|
42
|
+
} // pluginState
|
|
43
|
+
;
|
|
44
|
+
function resetState () {
|
|
45
|
+
pluginState.callbacks = {}
|
|
46
|
+
pluginState.typeFn = ''
|
|
47
|
+
pluginState.watchList = []
|
|
48
|
+
pluginState.wait = {}
|
|
49
|
+
} // resetState func.
|
|
50
|
+
|
|
51
|
+
// Read shortcuts names from all context entities and normalize entries related to the plugin
|
|
52
|
+
inAPI._normalizeWithPlugins ( _normalizeShortcutName )
|
|
53
|
+
let formListener = _listenDOM ( deps, pluginState );
|
|
54
|
+
|
|
55
|
+
if ( currentContext.name ) {
|
|
56
|
+
let hasFormShortcuts = _registerShortcutEvents ( deps, pluginState )
|
|
57
|
+
if ( hasFormShortcuts ) formListener.start ()
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
let pluginAPI = {
|
|
61
|
+
getPrefix : ( ) => 'form'
|
|
62
|
+
, shortcutName : key => { // Format a key string according plugin needs
|
|
63
|
+
return _normalizeShortcutName ( key )
|
|
64
|
+
}
|
|
65
|
+
, contextChange : ( ) => {
|
|
66
|
+
resetState ()
|
|
67
|
+
let hasFormShortcuts = _registerShortcutEvents ( deps, pluginState )
|
|
68
|
+
if ( hasFormShortcuts ) formListener.start ()
|
|
69
|
+
else formListener.stop ()
|
|
70
|
+
}
|
|
71
|
+
, mute : () => formListener.stop ()
|
|
72
|
+
, unmute : () => formListener.start ()
|
|
73
|
+
, destroy : () => {
|
|
74
|
+
formListener.stop ()
|
|
75
|
+
pluginState = null
|
|
76
|
+
pluginAPI = null
|
|
77
|
+
}
|
|
78
|
+
}; // pluginAPI
|
|
79
|
+
Object.freeze ( pluginAPI )
|
|
80
|
+
return pluginAPI
|
|
81
|
+
} // pluginForm func.
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
export default pluginForm
|
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
import { beforeEach, describe, it, test } from 'vitest'
|
|
2
|
+
import { userEvent } from '@vitest/browser/context'
|
|
3
|
+
|
|
4
|
+
import Block from '../test-components/Block.jsx'
|
|
5
|
+
import VisaulController from '@peter.naydenov/visual-controller-for-react'
|
|
6
|
+
import '../test-components/style.css'
|
|
7
|
+
|
|
8
|
+
import {
|
|
9
|
+
pluginClick,
|
|
10
|
+
pluginKey
|
|
11
|
+
, pluginForm
|
|
12
|
+
, shortcuts
|
|
13
|
+
} from '../src/main.js'
|
|
14
|
+
import { expect } from 'chai'
|
|
15
|
+
|
|
16
|
+
import askForPromise from 'ask-for-promise'
|
|
17
|
+
|
|
18
|
+
const html = new VisaulController ();
|
|
19
|
+
|
|
20
|
+
let
|
|
21
|
+
a = false
|
|
22
|
+
, b = false
|
|
23
|
+
;
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
function wait (ms) {
|
|
27
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const short = shortcuts ({onShortcut : ( shortcut, {context,note,type}) => console.log (shortcut, context, note, type) });
|
|
31
|
+
|
|
32
|
+
short.load ({
|
|
33
|
+
general : {
|
|
34
|
+
' key : shift+a': [ () => a = true ]
|
|
35
|
+
}
|
|
36
|
+
, extra : {
|
|
37
|
+
'key : p,r,o,b,a': () => b = true
|
|
38
|
+
}
|
|
39
|
+
, extend : {
|
|
40
|
+
'form : watch' : () => 'input'
|
|
41
|
+
, 'form : define' : () => 'input'
|
|
42
|
+
, 'form : action' : () => [
|
|
43
|
+
{
|
|
44
|
+
fn : (e) => console.log ( e.target )
|
|
45
|
+
, type : 'input'
|
|
46
|
+
, mode : 'in'
|
|
47
|
+
}
|
|
48
|
+
]
|
|
49
|
+
}
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
beforeEach ( () => {
|
|
53
|
+
let container = document.createElement ( 'div' )
|
|
54
|
+
container.id = 'app'
|
|
55
|
+
document.body.appendChild ( container )
|
|
56
|
+
html.publish ( Block, {}, 'app' )
|
|
57
|
+
a = false, b = false
|
|
58
|
+
}) // beforeEach
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
describe ( "Shortcuts", () => {
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
test ( 'Shortcut if no plugin installed', () => {
|
|
69
|
+
let res = new Promise ( (resolve,reject) => {
|
|
70
|
+
short.changeContext ( 'general' )
|
|
71
|
+
let r = short.listShortcuts ('general')
|
|
72
|
+
expect ( r[0]).to.equal ( ' key : shift+a' ) // Shortcut name is the same as it was set
|
|
73
|
+
resolve ('success')
|
|
74
|
+
})
|
|
75
|
+
return res
|
|
76
|
+
}) // test no plugin installed
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
test ( 'Key plugin, no context selected', () => {
|
|
81
|
+
const res = new Promise ( ( resolve ) => {
|
|
82
|
+
short.enablePlugin ( pluginKey )
|
|
83
|
+
const r = short.listShortcuts ( 'general' )
|
|
84
|
+
expect ( r[0] ).to.equal ( 'KEY:A+SHIFT' ) // Shortcut name is recognized by plugin and is normalized
|
|
85
|
+
resolve ('success')
|
|
86
|
+
})
|
|
87
|
+
return res
|
|
88
|
+
}) // test key plugin installed, no context selected
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
test ( 'Key plugin with context selected', () => {
|
|
93
|
+
const res = new Promise ( (resolve) => {
|
|
94
|
+
short.enablePlugin ( pluginKey )
|
|
95
|
+
short.changeContext ( 'general' )
|
|
96
|
+
const r = short.listShortcuts ('general')
|
|
97
|
+
expect ( r[0] ).to.equal ( 'KEY:A+SHIFT' ) // Shortcut name is recognized by plugin and is normalized
|
|
98
|
+
resolve ( 'success' )
|
|
99
|
+
})
|
|
100
|
+
return res
|
|
101
|
+
}) // test key plugin installed with context selected
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
test ( 'Simple shortcut', () => {
|
|
106
|
+
const res = new Promise ( (resolve) => {
|
|
107
|
+
short.enablePlugin ( pluginKey )
|
|
108
|
+
short.changeContext ()
|
|
109
|
+
short.changeContext ( 'general' )
|
|
110
|
+
userEvent.keyboard ( '{Shift>}a</Shift>' )
|
|
111
|
+
expect ( a ).to.be.false
|
|
112
|
+
wait ( 1000 )
|
|
113
|
+
.then ( () => { // Default wait sequence timeout is 480 ms, but maxSequence is 1, so we don't need to wait for timeout
|
|
114
|
+
expect ( a ).to.be.true
|
|
115
|
+
resolve ( 'success' )
|
|
116
|
+
})
|
|
117
|
+
})
|
|
118
|
+
return res
|
|
119
|
+
}) // test simple shortcut
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
test ( 'Call sequence shortcut', async () => {
|
|
124
|
+
let res = new Promise ( async (resolve) => {
|
|
125
|
+
b = false
|
|
126
|
+
short.enablePlugin ( pluginKey )
|
|
127
|
+
short.changeContext ()
|
|
128
|
+
short.changeContext ( 'extra' )
|
|
129
|
+
await userEvent.keyboard ( 'proba' )
|
|
130
|
+
expect ( b ).to.be.true
|
|
131
|
+
resolve ( 'success' )
|
|
132
|
+
})
|
|
133
|
+
return res
|
|
134
|
+
}) // test call sequence shortcut
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
test ( 'Single mouse click', done => {
|
|
139
|
+
const res = new Promise ( async (resolve) => {
|
|
140
|
+
expect ( a ).to.be.false
|
|
141
|
+
expect ( b ).to.be.false
|
|
142
|
+
short.enablePlugin ( pluginClick )
|
|
143
|
+
|
|
144
|
+
short.load ({ 'extra' : {
|
|
145
|
+
' cLIck : left - 1 ' : () => a = true // Check if spaces, letter case can break the shortcut recognition
|
|
146
|
+
}
|
|
147
|
+
})
|
|
148
|
+
short.changeContext ()
|
|
149
|
+
short.changeContext ( 'extra' )
|
|
150
|
+
wait ( 100 )
|
|
151
|
+
.then ( async () => {
|
|
152
|
+
// Default wait mouse timeout is 320 ms, but maxClicks is 1, so we don't need to wait for timeout
|
|
153
|
+
let loc = document.querySelector('#rspan') || false
|
|
154
|
+
if ( loc ) await userEvent.click ( loc )
|
|
155
|
+
expect ( a ).to.be.true
|
|
156
|
+
resolve ( 'success' )
|
|
157
|
+
})
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
})
|
|
161
|
+
return res
|
|
162
|
+
}) // test single mouse click
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
test ( 'Double mouse click', () => {
|
|
167
|
+
let res = new Promise ( async (resolve) => {
|
|
168
|
+
expect ( a ).to.be.false
|
|
169
|
+
expect ( b ).to.be.false
|
|
170
|
+
|
|
171
|
+
short.enablePlugin ( pluginClick )
|
|
172
|
+
short.changeContext ( 'extra' )
|
|
173
|
+
short.load ({ // load will restart the selected context
|
|
174
|
+
'extra' : { // load will overwrite existing 'extra' context definition
|
|
175
|
+
'click: left-2' : () => a = true
|
|
176
|
+
}
|
|
177
|
+
})
|
|
178
|
+
wait ( 350 )
|
|
179
|
+
.then ( async () => { // Default wait mouse timeout is 320 ms
|
|
180
|
+
let loc = document.querySelector ( '#rspan' ) || false
|
|
181
|
+
// Third click is ignored. Max clicks according definition is 2.
|
|
182
|
+
if ( loc ) await userEvent.tripleClick ( loc )
|
|
183
|
+
expect ( a ).to.be.true
|
|
184
|
+
resolve ( 'success' )
|
|
185
|
+
})
|
|
186
|
+
})
|
|
187
|
+
return res
|
|
188
|
+
}) // test double mouse click
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
test ( 'Dependencies on shortcuts', () => {
|
|
193
|
+
const res = new Promise ( async (resolve) => {
|
|
194
|
+
const task = askForPromise ();
|
|
195
|
+
expect ( a ).to.be.false
|
|
196
|
+
expect ( b ).to.be.false
|
|
197
|
+
|
|
198
|
+
short.enablePlugin ( pluginClick )
|
|
199
|
+
short.setDependencies ({ task })
|
|
200
|
+
|
|
201
|
+
short.load ({
|
|
202
|
+
'extra' : { // load will overwrite existing 'extra' context definition
|
|
203
|
+
'click: left-1' : ({dependencies}) => {
|
|
204
|
+
const { task } = dependencies;
|
|
205
|
+
expect ( task ).to.have.property ( 'done' )
|
|
206
|
+
expect ( task ).to.have.property ( 'promise' )
|
|
207
|
+
a = true
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}) // load will restart the selected context
|
|
211
|
+
short.changeContext ( 'extra' )
|
|
212
|
+
wait ( 350 ) // Default wait mouse timeout is 320 ms
|
|
213
|
+
.then ( async () => {
|
|
214
|
+
let loc = document.querySelector ( '#rspan' ) || false
|
|
215
|
+
if ( loc ) await userEvent.click ( loc )
|
|
216
|
+
resolve ( 'success' )
|
|
217
|
+
})
|
|
218
|
+
}) // res promise
|
|
219
|
+
return res
|
|
220
|
+
}) // test dependencies on shortcuts
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
test ( 'Emit custom event', () => {
|
|
225
|
+
const res = new Promise ( async (resolve) => {
|
|
226
|
+
let result = null;
|
|
227
|
+
short.changeContext ()
|
|
228
|
+
short.enablePlugin ( pluginClick )
|
|
229
|
+
const myAllContext = {
|
|
230
|
+
myAll: {
|
|
231
|
+
'click : leff-1' : () => console.log ( 'nothing' )
|
|
232
|
+
, 'yo' : ({msg}) => result = msg
|
|
233
|
+
}}
|
|
234
|
+
short.load ( myAllContext )
|
|
235
|
+
short.changeContext ( 'myAll' )
|
|
236
|
+
short.emit ( 'yo', { context: short.getContext(), note: 'tt', type:'custom', msg:'hello' })
|
|
237
|
+
expect ( result ).to.be.equal ( 'hello' )
|
|
238
|
+
short.changeContext ( 'general' )
|
|
239
|
+
short.unload ( 'myAll' )
|
|
240
|
+
resolve ( 'success' )
|
|
241
|
+
})
|
|
242
|
+
return res
|
|
243
|
+
}) // test emit custom event
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
test ( 'List shortcuts', () => {
|
|
248
|
+
short.enablePlugin ( pluginKey )
|
|
249
|
+
let general = short.listShortcuts ('general');
|
|
250
|
+
expect ( general ).to.be.an ( 'array' )
|
|
251
|
+
expect ( general ).to.have.lengthOf ( 1 )
|
|
252
|
+
expect ( general[0] ).to.be.equal ( 'KEY:A+SHIFT' )
|
|
253
|
+
|
|
254
|
+
let fail = short.listShortcuts ( 'somethingNotExisting' );
|
|
255
|
+
expect ( fail ).to.be.null
|
|
256
|
+
|
|
257
|
+
let all = short.listShortcuts ();
|
|
258
|
+
expect ( all ).to.be.an ( 'array' )
|
|
259
|
+
|
|
260
|
+
expect ( all ).to.have.lengthOf ( 3 )
|
|
261
|
+
expect ( all[0] ).to.have.property ( 'context' )
|
|
262
|
+
expect ( all[0] ).to.have.property ( 'shortcuts' )
|
|
263
|
+
expect ( all[0].shortcuts ).to.be.an('array')
|
|
264
|
+
expect ( all[0].shortcuts ).to.have.lengthOf ( 1 )
|
|
265
|
+
expect ( all[0].shortcuts[0] ).to.be.equal ( 'KEY:A+SHIFT' )
|
|
266
|
+
expect ( all[0].context ).to.be.equal ( 'general' )
|
|
267
|
+
}) // test list shortcuts
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
test ( 'Click on anchor', () => {
|
|
272
|
+
const res = new Promise ( async (resolve) => {
|
|
273
|
+
// Click on anchor that don't have click-data attribute.
|
|
274
|
+
let result = 'none';
|
|
275
|
+
short.enablePlugin ( pluginClick )
|
|
276
|
+
short.load ({ 'extra' : {
|
|
277
|
+
'click: 1 - left' : ({target, context, event }) => { // Order of button name and number of click is not important
|
|
278
|
+
event.preventDefault ()
|
|
279
|
+
expect ( context ).to.be.equal ( 'extra' )
|
|
280
|
+
expect ( target.nodeName ).to.be.equal ( 'A' )
|
|
281
|
+
result = target.nodeName
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
})
|
|
285
|
+
short.changeContext ( 'extra' )
|
|
286
|
+
wait ( 10 )
|
|
287
|
+
.then ( async () => {
|
|
288
|
+
let loc = document.querySelector ( '#anchor' ) || false;
|
|
289
|
+
if ( loc ) await userEvent.click ( loc )
|
|
290
|
+
expect ( result ).to.be.equal ( 'A' )
|
|
291
|
+
short.changeContext ( 'general' )
|
|
292
|
+
resolve ( 'success' )
|
|
293
|
+
})
|
|
294
|
+
})
|
|
295
|
+
return res
|
|
296
|
+
}) // test click on anchor
|
|
297
|
+
|
|
298
|
+
}) // describe
|
|
299
|
+
|
|
@@ -3,6 +3,8 @@ return <>
|
|
|
3
3
|
<div className="block" data-click="red"><span id='rspan'>Red</span> </div>
|
|
4
4
|
<button className="big-btn" data-click="mega">Mega button</button>
|
|
5
5
|
<p>Some text with <a href="#" target="_blank">link <span id="anchor">in</span></a> it</p>
|
|
6
|
+
<p><input id="name" type="text" /></p>
|
|
7
|
+
<p><input type="text" id="age" /></p>
|
|
6
8
|
</>
|
|
7
9
|
}
|
|
8
10
|
|
|
@@ -0,0 +1,11 @@
|
|
|
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
|
+
})
|
|
@@ -0,0 +1,19 @@
|
|
|
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
|
+
])
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
// ***********************************************
|
|
2
|
-
// This example commands.js shows you how to
|
|
3
|
-
// create various custom commands and overwrite
|
|
4
|
-
// existing commands.
|
|
5
|
-
//
|
|
6
|
-
// For more comprehensive examples of custom
|
|
7
|
-
// commands please read more here:
|
|
8
|
-
// https://on.cypress.io/custom-commands
|
|
9
|
-
// ***********************************************
|
|
10
|
-
//
|
|
11
|
-
//
|
|
12
|
-
// -- This is a parent command --
|
|
13
|
-
// Cypress.Commands.add('login', (email, password) => { ... })
|
|
14
|
-
//
|
|
15
|
-
//
|
|
16
|
-
// -- This is a child command --
|
|
17
|
-
// Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... })
|
|
18
|
-
//
|
|
19
|
-
//
|
|
20
|
-
// -- This is a dual command --
|
|
21
|
-
// Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... })
|
|
22
|
-
//
|
|
23
|
-
//
|
|
24
|
-
// -- This will overwrite an existing command --
|
|
25
|
-
// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... })
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html>
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="utf-8">
|
|
5
|
-
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
6
|
-
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
|
7
|
-
<title>Components App</title>
|
|
8
|
-
<!-- Used by Next.js to inject CSS. -->
|
|
9
|
-
<div id="__next_css__DO_NOT_USE__"></div>
|
|
10
|
-
</head>
|
|
11
|
-
<body>
|
|
12
|
-
<div data-cy-root></div>
|
|
13
|
-
</body>
|
|
14
|
-
</html>
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
// ***********************************************************
|
|
2
|
-
// This example support/component.js is processed and
|
|
3
|
-
// loaded automatically before your test files.
|
|
4
|
-
//
|
|
5
|
-
// This is a great place to put global configuration and
|
|
6
|
-
// behavior that modifies Cypress.
|
|
7
|
-
//
|
|
8
|
-
// You can change the location of this file or turn off
|
|
9
|
-
// automatically serving support files with the
|
|
10
|
-
// 'supportFile' configuration option.
|
|
11
|
-
//
|
|
12
|
-
// You can read more here:
|
|
13
|
-
// https://on.cypress.io/configuration
|
|
14
|
-
// ***********************************************************
|
|
15
|
-
|
|
16
|
-
// Import commands.js using ES2015 syntax:
|
|
17
|
-
import './commands'
|
|
18
|
-
|
|
19
|
-
// Alternatively you can use CommonJS syntax:
|
|
20
|
-
// require('./commands')
|
|
21
|
-
|
|
22
|
-
import { mount } from 'cypress/react18'
|
|
23
|
-
|
|
24
|
-
Cypress.Commands.add('mount', mount)
|
|
25
|
-
|
|
26
|
-
// Example use:
|
|
27
|
-
// cy.mount(<MyComponent />)
|
package/cypress/support/e2e.js
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
// ***********************************************************
|
|
2
|
-
// This example support/e2e.js is processed and
|
|
3
|
-
// loaded automatically before your test files.
|
|
4
|
-
//
|
|
5
|
-
// This is a great place to put global configuration and
|
|
6
|
-
// behavior that modifies Cypress.
|
|
7
|
-
//
|
|
8
|
-
// You can change the location of this file or turn off
|
|
9
|
-
// automatically serving support files with the
|
|
10
|
-
// 'supportFile' configuration option.
|
|
11
|
-
//
|
|
12
|
-
// You can read more here:
|
|
13
|
-
// https://on.cypress.io/configuration
|
|
14
|
-
// ***********************************************************
|
|
15
|
-
|
|
16
|
-
// Import commands.js using ES2015 syntax:
|
|
17
|
-
import './commands'
|
|
18
|
-
|
|
19
|
-
// Alternatively you can use CommonJS syntax:
|
|
20
|
-
// require('./commands')
|