@qavajs/cypress 0.1.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 ADDED
@@ -0,0 +1,15 @@
1
+ # Change Log
2
+
3
+ All notable changes to the "@qavajs/cypress" will be documented in this file.
4
+
5
+ Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how to structure this file.
6
+
7
+ :rocket: - new feature
8
+ :beetle: - bugfix
9
+ :x: - deprecation/removal
10
+ :pencil: - chore
11
+ :microscope: - experimental
12
+
13
+ ## [0.1.0]
14
+ - :rocket: initial implementation
15
+
package/README.md ADDED
@@ -0,0 +1,50 @@
1
+ # @qavajs/cypress
2
+ qavajs implementation on top of cypress runner
3
+
4
+ ## Installation
5
+
6
+ `npm install @qavajs/cypress`
7
+ `npm install @qavajs/cypress-runner-adapter`
8
+
9
+ ## Configuration
10
+ cypress.config.js
11
+ ```javascript
12
+ const { defineConfig } = require('cypress');
13
+ const cucumber = require('@qavajs/cypress-runner-adapter/adapter');
14
+ module.exports = defineConfig({
15
+ e2e: {
16
+ specPattern: 'cypress/features/**/*.feature', //path to features
17
+ supportFile: 'cypress/support/e2e.js', //path to main support file
18
+ setupNodeEvents(on, config) {
19
+ on('file:preprocessor', cucumber)
20
+ },
21
+ },
22
+ });
23
+
24
+ ```
25
+ support file
26
+ ```typescript
27
+ import defineQavajs from '@qavajs/cypress/defineQavajs';
28
+ import '@qavajs/cypress';
29
+
30
+ import PageObject from '../page_object/'; // path to qavajs page objects
31
+ import Memory from '../memory'; // path to qavajs memory
32
+
33
+ defineQavajs({
34
+ pageObject: new PageObject(),
35
+ memory: new Memory()
36
+ });
37
+
38
+
39
+ ```
40
+
41
+ ## Development and testing
42
+ Install dependencies
43
+ `npm install`
44
+
45
+
46
+ Execute tests
47
+ `npm run test`
48
+
49
+ Debug tests
50
+ `npm run debug`
@@ -0,0 +1,2 @@
1
+ import { defineQavajs } from './lib/defineQavajs';
2
+ export default defineQavajs;
package/index.js ADDED
@@ -0,0 +1,9 @@
1
+ import './lib/types.js';
2
+ import './lib/setup.js';
3
+ import './lib/actions.js';
4
+ import './lib/validation.js';
5
+ import './lib/memory.js';
6
+ import './lib/valueValidation.js';
7
+ import './lib/execute.js';
8
+ import './lib/storage.js';
9
+ import './lib/mouseActions.js';
package/lib/actions.js ADDED
@@ -0,0 +1,274 @@
1
+ import { When } from '@qavajs/cypress-runner-adapter';
2
+ import { parseCoords } from './utils';
3
+
4
+ /**
5
+ * Opens provided url
6
+ * @param {string} url - url to navigate
7
+ * @example I open 'https://google.com'
8
+ */
9
+ When('I open {string} url', function (url) {
10
+ const urlValue = this.value(url);
11
+ cy.visit(urlValue);
12
+ });
13
+
14
+ /**
15
+ * Type text to element
16
+ * @param {string} alias - element to type
17
+ * @param {string} value - value to type
18
+ * @example I type 'wikipedia' to 'Google Input'
19
+ */
20
+ When('I type {string} to {string}', function (value, alias) {
21
+ const element = this.element(alias);
22
+ const typeValue = this.value(value);
23
+ element.type(typeValue);
24
+ });
25
+ //
26
+ /**
27
+ * Click element
28
+ * @param {string} alias - element to click
29
+ * @example I click 'Google Button'
30
+ */
31
+ When('I click {string}', function (alias) {
32
+ const element = this.element(alias);
33
+ element.click();
34
+ });
35
+
36
+ /**
37
+ * Click element via script
38
+ * @param {string} alias - element to click
39
+ * @example I force click 'Google Button'
40
+ */
41
+ When('I force click {string}', function (alias) {
42
+ const element = this.element(alias);
43
+ element.click({force: true});
44
+ });
45
+
46
+ /**
47
+ * Right click element
48
+ * @param {string} alias - element to right click
49
+ * @example I right click 'Google Button'
50
+ */
51
+ When('I right click {string}', function (alias) {
52
+ const element = this.element(alias);
53
+ element.rightclick();
54
+ });
55
+
56
+ /**
57
+ * Double click element
58
+ * @param {string} alias - double element to click
59
+ * @example I double click 'Google Button'
60
+ */
61
+ When('I double click {string}', function (alias) {
62
+ const element = this.element(alias);
63
+ element.dblclick();
64
+ });
65
+
66
+ /**
67
+ * Clear input
68
+ * @param {string} alias - element to clear
69
+ * @example I clear 'Google Input'
70
+ */
71
+ When('I clear {string}', function (alias) {
72
+ const element = this.element(alias);
73
+ element.clear();
74
+ });
75
+
76
+ /**
77
+ * Switch to parent frame
78
+ * @example I switch to parent frame
79
+ */
80
+ When('I switch to parent frame', function () {
81
+ this.po.driver = cy;
82
+ });
83
+
84
+ /**
85
+ * Switch to frame by index
86
+ * @param {number} index - index to switch
87
+ * @example I switch to 2 frame
88
+ */
89
+ When('I switch to {int} frame', function (index) {
90
+ const root = this.po.driver === cy ? cy.get('iframe') : this.po.driver.find('iframe');
91
+ this.po.driver = root
92
+ .eq(0)
93
+ .then((iframe) => iframe.contents())
94
+ .should('exist')
95
+ .find('body');
96
+ });
97
+
98
+ /**
99
+ * Switch to frame by alias
100
+ * @param {string} index - alias to switch
101
+ * @example I switch to 'IFrame' frame
102
+ */
103
+ When('I switch to {string} frame', function (frameAlias) {
104
+ const frame = this.element(frameAlias);
105
+ this.po.driver = frame
106
+ .then((iframe) => iframe.contents())
107
+ .should('exist')
108
+ .find('body');
109
+ });
110
+
111
+ /**
112
+ * Refresh current page
113
+ * @example I r efresh page
114
+ */
115
+ When('I refresh page', function () {
116
+ cy.reload();
117
+ });
118
+
119
+ /**
120
+ * Press button
121
+ * @param {string} key - key to press
122
+ * @example I press 'Enter' key
123
+ * @example I press 'Control+C' keys
124
+ */
125
+ When('I press {string} key(s)', function (key) {
126
+ cy.get('body').type(key);
127
+ });
128
+
129
+ /**
130
+ * Press button given number of times
131
+ * @param {string} key - key to press
132
+ * @param {number} num - number of times
133
+ * @example I press 'Enter' key 5 times
134
+ * @example I press 'Control+V' keys 5 times
135
+ */
136
+ When('I press {string} key(s) {int} time(s)', function (key, num) {
137
+ for (let i = 0; i < num; i++) {
138
+ cy.get('body').type(key);
139
+ }
140
+ });
141
+
142
+ /**
143
+ * Hover over element
144
+ * @param {string} alias - element to hover over
145
+ * @example I hover over 'Google Button'
146
+ */
147
+ When('I hover over {string}', function (alias) {
148
+ const element = this.element(alias);
149
+ element.trigger('mouseenter');
150
+ element.trigger('mouseover');
151
+ element.trigger('mousemove');
152
+ });
153
+
154
+ /**
155
+ * Select option with certain text from select element
156
+ * @param {string} option - option to select
157
+ * @param {string} alias - alias of select
158
+ * @example I select '1900' option from 'Registration Form > Date Of Birth'
159
+ * @example I select '$dateOfBirth' option from 'Registration Form > Date Of Birth' dropdown
160
+ */
161
+ When('I select {string} option from {string} dropdown', function (option, alias) {
162
+ const optionValue = this.value(option);
163
+ const select = this.element(alias);
164
+ select.select(optionValue);
165
+ });
166
+
167
+ /**
168
+ * Select option with certain text from select element
169
+ * @param {number} optionIndex - index of option to select
170
+ * @param {string} alias - alias of select
171
+ * @example I select 1 option from 'Registration Form > Date Of Birth' dropdown
172
+ */
173
+ When('I select {int}(st|nd|rd|th) option from {string} dropdown', function (optionIndex, alias) {
174
+ const select = this.element(alias);
175
+ select.select(optionIndex - 1);
176
+ });
177
+ //
178
+ /**
179
+ * Click on element with desired text in collection
180
+ * @param {string} expectedText - text to click
181
+ * @param {string} alias - collection to search text
182
+ * @example I click 'google' text in 'Search Engines' collection
183
+ * @example I click '$someVarWithText' text in 'Search Engines' collection
184
+ */
185
+ When(
186
+ 'I click {string} text in {string} collection',
187
+ function (value, alias) {
188
+ const resolvedValue = this.value(value);
189
+ const collection = this.element(alias);
190
+ collection.filter(`:contains(${resolvedValue})`).click();
191
+ }
192
+ );
193
+
194
+ /**
195
+ * Scroll by provided offset
196
+ * @param {string} - offset string in 'x, y' format
197
+ * @example
198
+ * When I scroll by '0, 100'
199
+ */
200
+ When('I scroll by {string}', function (offset) {
201
+ const [x, y] = parseCoords(this.value(offset));
202
+ cy.scrollTo(x, y);
203
+ });
204
+
205
+ /**
206
+ * Scroll by provided offset in element
207
+ * @param {string} - offset string in 'x, y' format
208
+ * @param {string} - element alias
209
+ * @example
210
+ * When I scroll by '0, 100' in 'Overflow Container'
211
+ */
212
+ When('I scroll by {string} in {string}', function (offset, alias) {
213
+ const [x, y] = parseCoords(this.value(offset));
214
+ const element = this.element(alias);
215
+ element.scrollTo(x, y);
216
+ });
217
+
218
+ /**
219
+ * Scroll to certain element
220
+ * @param {string} - element alias
221
+ * @example
222
+ * When I scroll to 'Some Element'
223
+ */
224
+ When('I scroll to {string}', function (alias) {
225
+ const element = this.element(alias);
226
+ element.scrollIntoView()
227
+ });
228
+
229
+
230
+ /**
231
+ * Provide file url to upload input
232
+ * @param {string} alias - element to upload file
233
+ * @param {string} value - file path
234
+ * @example I upload '/folder/file.txt' to 'File Input'
235
+ */
236
+ When('I upload {string} file to {string}', function (value, alias) {
237
+ const element = this.element(alias);
238
+ const filePath = this.value(value);
239
+ element.selectFile(filePath);
240
+ });
241
+
242
+ /**
243
+ * Accept alert
244
+ * @example I accept alert
245
+ */
246
+ When('I will accept alert', function () {
247
+ cy.window().then((win) => {
248
+ win.alert = () => true;
249
+ win.confirm = () => true;
250
+ });
251
+ });
252
+
253
+ /**
254
+ * Dismiss alert
255
+ * Cypress automatically dismisses all dialogs. This step is just to make it implicitly.
256
+ * @example I dismiss alert
257
+ */
258
+ When('I will dismiss alert', function () {
259
+ cy.window().then((win) => {
260
+ win.alert = () => false;
261
+ win.confirm = () => false;
262
+ });
263
+ });
264
+
265
+ /**
266
+ * I will type {string} to alert
267
+ * @example I type 'coffee' to alert
268
+ */
269
+ When('I will type {string} to alert', function (value) {
270
+ const resolvedValue = this.value(value);
271
+ cy.window().then((win) => {
272
+ win.prompt = () => resolvedValue;
273
+ });
274
+ });
@@ -0,0 +1,54 @@
1
+ chai.Assertion.addMethod('inViewport', function (ER) {
2
+ const subject = this._obj;
3
+
4
+ const windowInnerWidth = Cypress.config(`viewportWidth`);
5
+ const windowInnerHeight = Cypress.config(`viewportHeight`);
6
+
7
+ const bounding = subject.get(0).getBoundingClientRect();
8
+ const condition = bounding.top >= 0 &&
9
+ bounding.left >= 0 &&
10
+ bounding.right <= windowInnerWidth &&
11
+ bounding.bottom <= windowInnerHeight
12
+
13
+ this.assert(
14
+ condition,
15
+ 'expected #{this} to be in viewport',
16
+ 'expected #{this} not to be in viewport',
17
+ ER,
18
+ subject
19
+ );
20
+ });
21
+
22
+ export const conditionValidations = {
23
+ PRESENT: 'present',
24
+ VISIBLE: 'visible',
25
+ INVISIBLE: 'invisible',
26
+ ENABLED: 'enabled',
27
+ DISABLED: 'disabled',
28
+ IN_VIEWPORT: 'in viewport',
29
+ }
30
+
31
+ const notClause = '(not )?';
32
+ const toBeClause = 'to (?:be )?';
33
+ const validationClause = `(${Object.values(conditionValidations).join('|')})`;
34
+
35
+ export const conditionWaitExtractRegexp = new RegExp(`^${notClause}${toBeClause}${validationClause}$`);
36
+ export const conditionWaitRegexp = new RegExp(`(${notClause}${toBeClause}${validationClause})`);
37
+
38
+ const expects = {
39
+ [conditionValidations.PRESENT]: 'exist',
40
+ [conditionValidations.VISIBLE]: 'be.visible',
41
+ [conditionValidations.INVISIBLE]: 'be.hidden',
42
+ [conditionValidations.ENABLED]: 'be.enabled',
43
+ [conditionValidations.DISABLED]: 'be.disabled',
44
+ [conditionValidations.IN_VIEWPORT]: 'inViewport',
45
+ }
46
+
47
+ const not = (reverse) => reverse ? 'not.' : '';
48
+
49
+ export function getConditionExpect(condition) {
50
+ const match = condition.match(conditionWaitExtractRegexp);
51
+ if (!match) throw new Error(`${condition} wait is not implemented`);
52
+ const [ _, reverse, validation ] = match;
53
+ return not(reverse) + expects[validation];
54
+ }
@@ -0,0 +1,4 @@
1
+ export function defineQavajs(options) {
2
+ window.pageObject = options.pageObject;
3
+ window.memory = options.memory;
4
+ }
package/lib/execute.js ADDED
@@ -0,0 +1,69 @@
1
+ import { When } from '@qavajs/cypress-runner-adapter';
2
+
3
+ /**
4
+ * Execute client function
5
+ * @param {string} functionKey - memory key of function
6
+ * @example I execute '$fn' function // fn is function reference
7
+ * @example I execute 'window.scrollBy(0, 100)' function
8
+ */
9
+ When('I execute {string} function', function (functionKey) {
10
+ const fnContent = this.value(functionKey);
11
+ const fn = typeof fnContent === 'string' ? new Function(`return ${fnContent}`): fnContent;
12
+ cy.window().then(win => {
13
+ fn.apply(win);
14
+ });
15
+ });
16
+
17
+ /**
18
+ * Execute client function and save result into memory
19
+ * @param {string} functionKey - memory key of function
20
+ * @param {string} memoryKey - memory key to store result
21
+ * @example I execute '$fn' function and save result as 'result' // fn is function reference
22
+ * @example I execute 'window.scrollY' function and save result as 'scroll'
23
+ */
24
+ When('I execute {string} function and save result as {string}', function (functionKey, memoryKey) {
25
+ const fnContent = this.value(functionKey);
26
+ const fn = typeof fnContent === 'string' ? new Function(`return ${fnContent}`): fnContent;
27
+ cy.window().then(win => {
28
+ this.setValue(memoryKey, fn.apply(win));
29
+ });
30
+ });
31
+
32
+ /**
33
+ * Execute client function on certain element
34
+ * @param {string} functionKey - memory key of function
35
+ * @param {string} alias - alias of target element
36
+ * @example I execute '$fn' function on 'Component > Element' // fn is function reference
37
+ * @example I execute 'arguments[0].scrollIntoView()' function on 'Component > Element'
38
+ */
39
+ When('I execute {string} function on {string}', function (functionKey, alias) {
40
+ const element = this.element(alias);
41
+ const fnContent = this.value(functionKey);
42
+ const fn = typeof fnContent === 'string' ? new Function(`return ${fnContent}`): fnContent;
43
+ cy.window().then(win => {
44
+ element.then((e) => {
45
+ fn.apply(win, e);
46
+ });
47
+ });
48
+ });
49
+
50
+ /**
51
+ * Execute client function on certain element
52
+ * @param {string} functionKey - memory key of function
53
+ * @param {string} alias - alias of target element
54
+ * @example I execute '$fn' function on 'Component > Element' and save result as 'innerText' // fn is function reference
55
+ * @example I execute 'arguments[0].innerText' function on 'Component > Element' and save result as 'innerText'
56
+ */
57
+ When(
58
+ 'I execute {string} function on {string} and save result as {string}',
59
+ function (functionKey, alias, memoryKey) {
60
+ const element = this.element(alias);
61
+ const fnContent = this.value(functionKey);
62
+ const fn = typeof fnContent === 'string' ? new Function(`return ${fnContent}`): fnContent;
63
+ cy.window().then(win => {
64
+ element.then((e) => {
65
+ this.setValue(memoryKey, fn.apply(win, e));
66
+ });
67
+ });
68
+ }
69
+ );
package/lib/memory.js ADDED
@@ -0,0 +1,171 @@
1
+ import { When } from '@qavajs/cypress-runner-adapter';
2
+
3
+ /**
4
+ * Save text of element to memory
5
+ * @param {string} alias - element to get value
6
+ * @param {string} key - key to store value
7
+ * @example I save text of '#1 of Search Results' as 'firstSearchResult'
8
+ */
9
+ When('I save text of {string} as {string}', function (alias, key) {
10
+ const element = this.element(alias);
11
+ element.then((e) => {
12
+ this.setValue(key, e.text());
13
+ });
14
+ });
15
+
16
+ /**
17
+ * Save property of element to memory
18
+ * @param {string} property - property to store
19
+ * @param {string} alias - element to get value
20
+ * @param {string} key - key to store value
21
+ * @example I save 'checked' property of 'Checkbox' as 'checked'
22
+ * @example I save '$prop' property of 'Checkbox' as 'checked'
23
+ */
24
+ When('I save {string} property of {string} as {string}', function (property, alias, key) {
25
+ const element = this.element(alias);
26
+ const propertyName = this.value(property);
27
+ element.then((e) => {
28
+ this.setValue(key, e.prop(propertyName));
29
+ });
30
+ });
31
+
32
+ /**
33
+ * Save attribute of element to memory
34
+ * @param {string} attribute - attribute to store
35
+ * @param {string} alias - element to get value
36
+ * @param {string} key - key to store value
37
+ * @example I save 'href' attribute of 'Link' as 'linkHref'
38
+ * @example I save '$prop' attribute of 'Link' as 'linkHref'
39
+ */
40
+ When('I save {string} attribute of {string} as {string}', function (attribute, alias, key) {
41
+ const element = this.element(alias);
42
+ const attributeName = this.value(attribute);
43
+ element.then((e) => {
44
+ this.setValue(key, e.attr(attributeName));
45
+ });
46
+ });
47
+
48
+ /**
49
+ * Save number of elements in collection to memory
50
+ * @param {string} alias - collection to get value
51
+ * @param {string} key - key to store value
52
+ * @example I save number of elements in 'Search Results' as 'numberOfSearchResults'
53
+ */
54
+ When('I save number of elements in {string} collection as {string}', function (alias, key) {
55
+ const collection = this.element(alias);
56
+ collection.then((c) => {
57
+ this.setValue(key, c.length);
58
+ });
59
+ });
60
+
61
+ /**
62
+ * Save array of texts of collection to memory
63
+ * @param {string} alias - collection to get values
64
+ * @param {string} key - key to store value
65
+ * @example I save text of every element of 'Search Results' collection as 'searchResults'
66
+ */
67
+ When(
68
+ 'I save text of every element of {string} collection as {string}',
69
+ function (alias, key) {
70
+ const collection = this.element(alias);
71
+ collection.then((c) => {
72
+ const values = [];
73
+ c.each(function () {
74
+ values.push(Cypress.$(this).text());
75
+ })
76
+ this.setValue(key, values);
77
+ });
78
+ }
79
+ );
80
+
81
+ /**
82
+ * Save array of attributes of collection to memory
83
+ * @param {string} alias - collection to get values
84
+ * @param {string} key - key to store value
85
+ * @example I save 'checked' attribute of every element of 'Search > Checkboxes' collection as 'checkboxes'
86
+ */
87
+ When(
88
+ 'I save {string} attribute of every element of {string} collection as {string}',
89
+ function (attribute, alias, key) {
90
+ const collection = this.element(alias);
91
+ collection.then((c) => {
92
+ const values = [];
93
+ c.each(function () {
94
+ values.push(Cypress.$(this).attr(attribute));
95
+ })
96
+ this.setValue(key, values);
97
+ });
98
+ }
99
+ );
100
+
101
+ /**
102
+ * Save array of property of collection to memory
103
+ * @param {string} alias - collection to get values
104
+ * @param {string} key - key to store value
105
+ * @example I save 'href' property of every element of 'Search > Links' collection as 'hrefs'
106
+ */
107
+ When(
108
+ 'I save {string} property of every element of {string} collection as {string}',
109
+ function (property, alias, key) {
110
+ const collection = this.element(alias);
111
+ collection.then((c) => {
112
+ const values = [];
113
+ c.each(function () {
114
+ values.push(Cypress.$(this).prop(property));
115
+ })
116
+ this.setValue(key, values);
117
+ });
118
+ }
119
+ );
120
+
121
+ /**
122
+ * Save current url to memory
123
+ * @param {string} key - key to store value
124
+ * @example I save current url as 'currentUrl'
125
+ */
126
+ When('I save current url as {string}', function (key) {
127
+ cy.url().then((url) => {
128
+ this.setValue(key, url);
129
+ });
130
+ });
131
+
132
+ /**
133
+ * Save current page title to memory
134
+ * @param {string} key - key to store value
135
+ * @example I save page title as 'currentTitle'
136
+ */
137
+ When('I save page title as {string}', function (key) {
138
+ cy.title().then((title) => {
139
+ this.setValue(key, title);
140
+ });
141
+ });
142
+
143
+ /**
144
+ * Save css property of element to memory
145
+ * @param {string} property - property to store
146
+ * @param {string} alias - element to get value
147
+ * @param {string} key - key to store value
148
+ * @example I save 'color' css property of 'Checkbox' as 'checkboxColor'
149
+ * @example I save '$propertyName' property of 'Checkbox' as 'checkboxColor'
150
+ */
151
+ When('I save {string} css property of {string} as {string}', function (property, alias, key) {
152
+ const propertyName = this.value(property);
153
+ const element = this.element(alias);
154
+ element.then((e) => {
155
+ this.setValue(key, e.css(propertyName));
156
+ });
157
+ });
158
+
159
+ /**
160
+ * Save bounding client rect to memory
161
+ * https://developer.mozilla.org/en-US/docs/Web/API/DOMRect
162
+ * @param {string} alias - element to get value
163
+ * @param {string} key - key to store value
164
+ * @example
165
+ * When I save bounding rect of 'Node' as 'boundingRect'
166
+ * Then I expect '$boundingRect.width' to equal '42'
167
+ */
168
+ When('I save bounding rect of {string} as {string}', function (alias, key) {
169
+ const element = this.element(alias);
170
+ element.then(node => this.setValue(key, node.get(0).getBoundingClientRect()));
171
+ });