cypress-plugin-grep-boxes 1.1.2 → 2.0.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/README.md +13 -6
- package/assets/cy-grep-boxes-demo.gif +0 -0
- package/cypress/e2e/2-advanced-examples/window.cy.js +9 -5
- package/cypress/support/e2e.js +1 -3
- package/index.js +319 -160
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -6,11 +6,12 @@
|
|
|
6
6
|
A companion Cypress plugin for <code>cy-grep</code> that allows user to run specific test(s) in <code>open</code> mode.
|
|
7
7
|
</p>
|
|
8
8
|
|
|
9
|
-

|
|
10
10
|
|
|
11
11
|
## Features
|
|
12
12
|
|
|
13
13
|
- ✅ A new UI test selection within `cypress open` to filter and run only selected tests in a given spec
|
|
14
|
+
- 🚩 _NEW_ in v2.0.0: Tags are now displayed and can be clicked to filter by respective tag in `cypress open`
|
|
14
15
|
|
|
15
16
|
#### Table of Contents
|
|
16
17
|
|
|
@@ -27,6 +28,9 @@ A companion Cypress plugin for <code>cy-grep</code> that allows user to run spec
|
|
|
27
28
|
|
|
28
29
|
1. Install the following packages:
|
|
29
30
|
|
|
31
|
+
> [!NOTE]
|
|
32
|
+
> To support `cypress-plugin-grep-boxes` displaying test tags in the Cypress Test Runner, `@bahmutov/cy-grep` must be on version >= 2.1.0
|
|
33
|
+
|
|
30
34
|
```sh
|
|
31
35
|
npm install --save-dev @bahmutov/cy-grep # Dependent package for the plugin
|
|
32
36
|
npm install --save-dev cypress-plugin-grep-boxes
|
|
@@ -34,14 +38,14 @@ npm install --save-dev cypress-plugin-grep-boxes
|
|
|
34
38
|
|
|
35
39
|
2. In `cypress/support/e2e.js` (For E2E tests) and/or `cypress/support/component.js` (For Component tests),
|
|
36
40
|
|
|
41
|
+
> [!IMPORTANT]
|
|
42
|
+
> In the plugin version 2.0.0, the `e2e.js` (or `component.js`) support file import has been updated for simplicity:
|
|
43
|
+
|
|
37
44
|
```js
|
|
38
|
-
import
|
|
45
|
+
import 'cypress-plugin-grep-boxes';
|
|
39
46
|
import registerCypressGrep from '@bahmutov/cy-grep/src/support';
|
|
40
47
|
|
|
41
48
|
registerCypressGrep();
|
|
42
|
-
|
|
43
|
-
greppedTestToggle();
|
|
44
|
-
addGrepButtons();
|
|
45
49
|
```
|
|
46
50
|
|
|
47
51
|
---
|
|
@@ -64,7 +68,10 @@ addGrepButtons();
|
|
|
64
68
|
|
|
65
69
|
## ✅ Open mode
|
|
66
70
|
|
|
67
|
-
Within each spec
|
|
71
|
+
Within each spec in Cypress `open` mode:
|
|
72
|
+
|
|
73
|
+
- You can select any given number of individual test(s) and click the filter toggle located on the reporter above
|
|
74
|
+
- You can click on any available tag and run only tests in the spec with the respective tag
|
|
68
75
|
|
|
69
76
|

|
|
70
77
|
|
|
Binary file
|
|
@@ -10,12 +10,16 @@ context('Window', () => {
|
|
|
10
10
|
cy.window().should('have.property', 'top');
|
|
11
11
|
});
|
|
12
12
|
|
|
13
|
-
it(
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
it(
|
|
14
|
+
'cy.document() - get the document object',
|
|
15
|
+
{ tags: ['@sanity', '@smoke'] },
|
|
16
|
+
() => {
|
|
17
|
+
// https://on.cypress.io/document
|
|
18
|
+
cy.document().should('have.property', 'charset').and('eq', 'UTF-8');
|
|
19
|
+
}
|
|
20
|
+
);
|
|
17
21
|
|
|
18
|
-
it('cy.title() - get the title', () => {
|
|
22
|
+
it('cy.title() - get the title', { tags: '@title' }, () => {
|
|
19
23
|
// https://on.cypress.io/title
|
|
20
24
|
cy.title().should('include', 'Kitchen Sink');
|
|
21
25
|
});
|
package/cypress/support/e2e.js
CHANGED
|
@@ -15,12 +15,10 @@
|
|
|
15
15
|
|
|
16
16
|
// Import commands.js using ES2015 syntax:
|
|
17
17
|
import './commands';
|
|
18
|
-
import
|
|
18
|
+
import '../../index';
|
|
19
19
|
import registerCypressGrep from '@bahmutov/cy-grep/src/support';
|
|
20
20
|
|
|
21
21
|
registerCypressGrep();
|
|
22
|
-
greppedTestToggle();
|
|
23
|
-
addGrepButtons();
|
|
24
22
|
|
|
25
23
|
// Alternatively you can use CommonJS syntax:
|
|
26
24
|
// require('./commands')
|
package/index.js
CHANGED
|
@@ -1,15 +1,12 @@
|
|
|
1
|
-
import registerCypressGrep from '@bahmutov/cy-grep';
|
|
2
1
|
/**
|
|
3
2
|
* Adds a toggle to reporter to grep selected tests.
|
|
4
3
|
*/
|
|
5
4
|
|
|
6
5
|
const tests = [];
|
|
7
6
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
const hasToggleButton = window.top?.document.querySelector('#grepTestToggle');
|
|
12
|
-
const defaultStyles = `
|
|
7
|
+
const hasStyles = window.top?.document.querySelector('#grepTestToggleStyle');
|
|
8
|
+
const hasToggleButton = window.top?.document.querySelector('#grepTestToggle');
|
|
9
|
+
const defaultStyles = `
|
|
13
10
|
.reporter header {
|
|
14
11
|
overflow: visible;
|
|
15
12
|
z-index: 2;
|
|
@@ -24,6 +21,7 @@ export const greppedTestToggle = () => {
|
|
|
24
21
|
#grepTestToggleControls label {
|
|
25
22
|
background-color: transparent;
|
|
26
23
|
padding-top: 5px;
|
|
24
|
+
padding-right: 2px;
|
|
27
25
|
}
|
|
28
26
|
#grepTestToggleControls #grepTestToggleTooltip {
|
|
29
27
|
visibility: hidden;
|
|
@@ -34,13 +32,16 @@ export const greppedTestToggle = () => {
|
|
|
34
32
|
padding: 5px;
|
|
35
33
|
border-radius: 3px;
|
|
36
34
|
position: absolute;
|
|
37
|
-
z-index:
|
|
38
|
-
top:
|
|
39
|
-
|
|
35
|
+
z-index: 99999;
|
|
36
|
+
top: 33px;
|
|
37
|
+
right: -2px;
|
|
40
38
|
height: 28px;
|
|
39
|
+
overflow: visible;
|
|
41
40
|
}
|
|
42
41
|
#grepTestToggleControls:hover #grepTestToggleTooltip {
|
|
43
42
|
visibility: visible;
|
|
43
|
+
z-index: 99999;
|
|
44
|
+
overflow: visible;
|
|
44
45
|
}
|
|
45
46
|
#grepTestToggleButton #grepTestToggleLabel {
|
|
46
47
|
cursor: pointer;
|
|
@@ -49,145 +50,203 @@ export const greppedTestToggle = () => {
|
|
|
49
50
|
content: " ";
|
|
50
51
|
position: absolute;
|
|
51
52
|
bottom: 100%; /* At the top of the tooltip */
|
|
52
|
-
|
|
53
|
+
left: 89%;
|
|
54
|
+
z-index: 99999;
|
|
53
55
|
margin-left: -5px;
|
|
54
56
|
border-width: 5px;
|
|
55
57
|
border-style: solid;
|
|
58
|
+
overflow: visible;
|
|
56
59
|
border-color: transparent transparent #f3f4fa transparent;
|
|
57
60
|
}
|
|
58
61
|
.reporter:has(#grepTestToggle:checked) .command.command-name-request:has(.command-is-event) {
|
|
59
62
|
display:none
|
|
60
63
|
}
|
|
64
|
+
.spec-container {
|
|
65
|
+
overflow: visible !important
|
|
66
|
+
}
|
|
61
67
|
`;
|
|
62
|
-
|
|
68
|
+
const turnOngrepTestToggleIcon = `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="#afb3c7" class="bi bi-collection-play-fill" viewBox="0 0 16 16">
|
|
63
69
|
<path d="M2.5 3.5a.5.5 0 0 1 0-1h11a.5.5 0 0 1 0 1zm2-2a.5.5 0 0 1 0-1h7a.5.5 0 0 1 0 1zM0 13a1.5 1.5 0 0 0 1.5 1.5h13A1.5 1.5 0 0 0 16 13V6a1.5 1.5 0 0 0-1.5-1.5h-13A1.5 1.5 0 0 0 0 6zm6.258-6.437a.5.5 0 0 1 .507.013l4 2.5a.5.5 0 0 1 0 .848l-4 2.5A.5.5 0 0 1 6 12V7a.5.5 0 0 1 .258-.437"/>
|
|
64
70
|
</svg>`;
|
|
65
71
|
|
|
66
|
-
|
|
72
|
+
const turnOffgrepTestToggleIcon = `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="#afb3c7" class="bi bi-collection-play" viewBox="0 0 16 16">
|
|
67
73
|
<path d="M2 3a.5.5 0 0 0 .5.5h11a.5.5 0 0 0 0-1h-11A.5.5 0 0 0 2 3m2-2a.5.5 0 0 0 .5.5h7a.5.5 0 0 0 0-1h-7A.5.5 0 0 0 4 1m2.765 5.576A.5.5 0 0 0 6 7v5a.5.5 0 0 0 .765.424l4-2.5a.5.5 0 0 0 0-.848z"/>
|
|
68
74
|
<path d="M1.5 14.5A1.5 1.5 0 0 1 0 13V6a1.5 1.5 0 0 1 1.5-1.5h13A1.5 1.5 0 0 1 16 6v7a1.5 1.5 0 0 1-1.5 1.5zm13-1a.5.5 0 0 0 .5-.5V6a.5.5 0 0 0-.5-.5h-13A.5.5 0 0 0 1 6v7a.5.5 0 0 0 .5.5z"/>
|
|
69
75
|
</svg>`;
|
|
70
76
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
77
|
+
const turnOffgrepTestToggleDescription = 'Filter selected tests';
|
|
78
|
+
const turnOngrepTestToggleDescription = 'Unfilter selected tests';
|
|
79
|
+
|
|
80
|
+
// append styles
|
|
81
|
+
if (!hasStyles) {
|
|
82
|
+
let reporterEl;
|
|
83
|
+
const reporterStyleEl = document.createElement('style');
|
|
84
|
+
if (Cypress.version >= '15.0.0') {
|
|
85
|
+
reporterEl = window.top?.document.querySelector('.runnable-header');
|
|
86
|
+
} else {
|
|
87
|
+
reporterEl = window.top?.document.querySelector('#unified-reporter');
|
|
81
88
|
}
|
|
89
|
+
reporterStyleEl.setAttribute('id', 'grepTestToggleStyle');
|
|
90
|
+
reporterStyleEl.innerHTML = defaultStyles;
|
|
91
|
+
reporterEl?.appendChild(reporterStyleEl);
|
|
92
|
+
}
|
|
82
93
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
const headerToggleInput = document.createElement('input');
|
|
92
|
-
const headerToggleLabel = document.createElement('label');
|
|
93
|
-
|
|
94
|
-
headerToggleInput.setAttribute('type', 'checkbox');
|
|
95
|
-
|
|
96
|
-
headerToggleInput.setAttribute('id', 'grepTestToggle');
|
|
97
|
-
headerToggleLabel.setAttribute('for', 'grepTestToggle');
|
|
98
|
-
headerToggleLabel.setAttribute('id', 'grepTestToggleLabel');
|
|
99
|
-
headerToggleLabel.innerHTML = turnOffgrepTestToggleIcon;
|
|
100
|
-
|
|
101
|
-
headerToggleDiv.setAttribute('class', 'controls');
|
|
102
|
-
headerToggleDiv.setAttribute('id', 'grepTestToggleControls');
|
|
103
|
-
headerToggleTooltip.setAttribute('id', 'grepTestToggleTooltip');
|
|
104
|
-
headerToggleTooltip.innerText = turnOffgrepTestToggleDescription;
|
|
105
|
-
headerToggleButton.setAttribute(
|
|
106
|
-
'aria-label',
|
|
107
|
-
turnOffgrepTestToggleDescription
|
|
108
|
-
);
|
|
109
|
-
headerToggleButton.setAttribute('id', 'grepTestToggleButton');
|
|
110
|
-
|
|
111
|
-
header?.appendChild(headerToggleDiv);
|
|
112
|
-
headerToggleDiv?.appendChild(headerToggleSpan);
|
|
113
|
-
headerToggleDiv?.appendChild(headerToggleTooltip);
|
|
114
|
-
headerToggleSpan?.appendChild(headerToggleButton);
|
|
115
|
-
headerToggleButton?.appendChild(headerToggleInput);
|
|
116
|
-
headerToggleButton?.appendChild(headerToggleLabel);
|
|
94
|
+
if (!hasToggleButton) {
|
|
95
|
+
let header;
|
|
96
|
+
if (Cypress.version >= '15.0.0') {
|
|
97
|
+
// TODO: Cypress v15 GUI provides option for Cypress Studio which pushes the grep toggle button around the UI
|
|
98
|
+
// For simplicity, moving the toggle button to the spec container above the stop button
|
|
99
|
+
header = window.top?.document.querySelector('.runnable-header');
|
|
100
|
+
} else {
|
|
101
|
+
header = window.top?.document.querySelector('#unified-reporter header');
|
|
117
102
|
}
|
|
118
|
-
|
|
119
|
-
const
|
|
120
|
-
|
|
121
|
-
const
|
|
122
|
-
|
|
123
|
-
);
|
|
124
|
-
|
|
125
|
-
|
|
103
|
+
const headerToggleDiv = document.createElement('div');
|
|
104
|
+
const headerToggleSpan = document.createElement('span');
|
|
105
|
+
const headerToggleTooltip = document.createElement('span');
|
|
106
|
+
const headerToggleButton = document.createElement('button');
|
|
107
|
+
const headerToggleInput = document.createElement('input');
|
|
108
|
+
const headerToggleLabel = document.createElement('label');
|
|
109
|
+
|
|
110
|
+
headerToggleInput.setAttribute('type', 'checkbox');
|
|
111
|
+
|
|
112
|
+
headerToggleInput.setAttribute('id', 'grepTestToggle');
|
|
113
|
+
headerToggleLabel.setAttribute('for', 'grepTestToggle');
|
|
114
|
+
headerToggleLabel.setAttribute('id', 'grepTestToggleLabel');
|
|
115
|
+
headerToggleLabel.innerHTML = turnOffgrepTestToggleIcon;
|
|
116
|
+
|
|
117
|
+
headerToggleDiv.setAttribute('id', 'grepTestToggleControls');
|
|
118
|
+
headerToggleTooltip.setAttribute('id', 'grepTestToggleTooltip');
|
|
119
|
+
headerToggleTooltip.innerText = turnOffgrepTestToggleDescription;
|
|
120
|
+
headerToggleButton.setAttribute(
|
|
121
|
+
'aria-label',
|
|
122
|
+
turnOffgrepTestToggleDescription
|
|
126
123
|
);
|
|
124
|
+
headerToggleButton.setAttribute('id', 'grepTestToggleButton');
|
|
125
|
+
|
|
126
|
+
headerToggleDiv.setAttribute('class', 'controls');
|
|
127
|
+
header?.appendChild(headerToggleDiv);
|
|
128
|
+
headerToggleDiv?.appendChild(headerToggleSpan);
|
|
129
|
+
headerToggleDiv?.appendChild(headerToggleTooltip);
|
|
130
|
+
headerToggleSpan?.appendChild(headerToggleButton);
|
|
131
|
+
headerToggleButton?.appendChild(headerToggleInput);
|
|
132
|
+
headerToggleButton?.appendChild(headerToggleLabel);
|
|
133
|
+
}
|
|
127
134
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
135
|
+
const grepTestToggleElement =
|
|
136
|
+
window.top?.document.querySelector('#grepTestToggle');
|
|
137
|
+
const grepTestToggleLabelElement = window.top?.document.querySelector(
|
|
138
|
+
'[for=grepTestToggle]'
|
|
139
|
+
);
|
|
140
|
+
const grepTestToggleTooltipElement = window.top?.document.querySelector(
|
|
141
|
+
'#grepTestToggleTooltip'
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
grepTestToggleElement?.addEventListener('change', (e) => {
|
|
145
|
+
const stopBtn = window.top?.document.querySelector('.reporter .stop');
|
|
146
|
+
|
|
147
|
+
if (e.target.checked) {
|
|
148
|
+
if (stopBtn) {
|
|
149
|
+
stopBtn.click();
|
|
150
|
+
}
|
|
151
|
+
// store all checked checkbox values then send to grep in accepted format
|
|
152
|
+
const tests = [
|
|
153
|
+
...window.top?.document.querySelectorAll('.grep-test-checkbox:checked'),
|
|
154
|
+
].map((e) => e.value);
|
|
155
|
+
// store all non-checked checkbox values
|
|
156
|
+
const uncheckedTests = [
|
|
157
|
+
...window.top?.document.querySelectorAll(
|
|
158
|
+
'.grep-test-checkbox:not(:checked)'
|
|
159
|
+
),
|
|
160
|
+
].map((e) => e.value);
|
|
161
|
+
|
|
162
|
+
tests.forEach((t) => {
|
|
163
|
+
// if a checked test title begins with the grep inverted '-' symbol, remove the '-'
|
|
164
|
+
if (t[0] === '-') {
|
|
165
|
+
tests.push(t.slice(1));
|
|
166
|
+
tests.splice(
|
|
167
|
+
tests.findIndex((e) => e === t),
|
|
168
|
+
1
|
|
169
|
+
);
|
|
134
170
|
}
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
const uncheckedTests = [
|
|
141
|
-
...window.top?.document.querySelectorAll(
|
|
142
|
-
'.grep-test-checkbox:not(:checked)'
|
|
143
|
-
),
|
|
144
|
-
].map((e) => e.value);
|
|
145
|
-
|
|
146
|
-
tests.forEach((t) => {
|
|
147
|
-
// if a checked test title begins with the grep inverted '-' symbol, remove the '-'
|
|
148
|
-
if (t[0] === '-') {
|
|
149
|
-
tests.push(t.slice(1));
|
|
150
|
-
tests.splice(
|
|
151
|
-
tests.findIndex((e) => e === t),
|
|
152
|
-
1
|
|
153
|
-
);
|
|
171
|
+
|
|
172
|
+
// if a non-checked test's title includes a checked test's title, invert grep for unchecked title
|
|
173
|
+
uncheckedTests.forEach((u) => {
|
|
174
|
+
if (u.includes(t)) {
|
|
175
|
+
tests.push(`-${u}`);
|
|
154
176
|
}
|
|
155
|
-
// if a non-checked test's title includes a checked test's title, invert grep for unchecked title
|
|
156
|
-
uncheckedTests.forEach((u) => {
|
|
157
|
-
if (u.includes(t)) {
|
|
158
|
-
tests.push(`-${u}`);
|
|
159
|
-
}
|
|
160
|
-
});
|
|
161
177
|
});
|
|
178
|
+
});
|
|
162
179
|
|
|
163
|
-
|
|
180
|
+
Cypress.grep(tests.join(';'));
|
|
164
181
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
182
|
+
// when checked, grep only selected tests in spec
|
|
183
|
+
grepTestToggleLabelElement.innerHTML = turnOngrepTestToggleIcon;
|
|
184
|
+
grepTestToggleTooltipElement.innerHTML = turnOngrepTestToggleDescription;
|
|
185
|
+
} else {
|
|
186
|
+
if (stopBtn) {
|
|
187
|
+
stopBtn.click();
|
|
188
|
+
}
|
|
189
|
+
// when unchecked, ungrep and show all tests in spec
|
|
190
|
+
Cypress.grep();
|
|
191
|
+
grepTestToggleLabelElement.innerHTML = turnOffgrepTestToggleIcon;
|
|
192
|
+
grepTestToggleTooltipElement.innerHTML = turnOffgrepTestToggleDescription;
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
// Wrapping logic within isInteractive check
|
|
197
|
+
// This targets cypress open mode where user can switch specs
|
|
198
|
+
if (Cypress.config('isInteractive')) {
|
|
199
|
+
Cypress.on('window:unload', () => {
|
|
200
|
+
addTags();
|
|
201
|
+
// Store the current Cypress test runner url
|
|
202
|
+
// This is to check against any spec change in test runner while the grep filter is activated
|
|
203
|
+
// If a user does switch spec while filter is active, the filter will be reset
|
|
204
|
+
const sidebarSpecLinkPage = window.top?.document.querySelector(
|
|
205
|
+
'[data-cy="sidebar-link-specs-page"]'
|
|
206
|
+
);
|
|
207
|
+
const grepTestToggleElement =
|
|
208
|
+
window.top?.document.querySelector('#grepTestToggle');
|
|
209
|
+
|
|
210
|
+
if (
|
|
211
|
+
window.top?.document.URL !=
|
|
212
|
+
sidebarSpecLinkPage.getAttribute('data-url') &&
|
|
213
|
+
grepTestToggleElement.checked
|
|
214
|
+
) {
|
|
215
|
+
grepTestToggleElement.click();
|
|
176
216
|
}
|
|
217
|
+
|
|
218
|
+
sidebarSpecLinkPage.setAttribute('data-url', window.top?.document.URL);
|
|
177
219
|
});
|
|
178
|
-
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
if (Cypress.config('isInteractive')) {
|
|
223
|
+
if (
|
|
224
|
+
// if the grep test toggle is not checked, do not run tests
|
|
225
|
+
Cypress.env('disableInitialAutoRun') &&
|
|
226
|
+
window.top?.document.querySelectorAll('#grepTestToggle:checked').length ===
|
|
227
|
+
0
|
|
228
|
+
) {
|
|
229
|
+
const sidebarSpecLinkPage = window.top?.document.querySelector(
|
|
230
|
+
'[data-cy="sidebar-link-specs-page"]'
|
|
231
|
+
);
|
|
232
|
+
|
|
233
|
+
sidebarSpecLinkPage.setAttribute('data-url', window.top?.document.URL);
|
|
234
|
+
Cypress.runner.stop();
|
|
235
|
+
}
|
|
236
|
+
}
|
|
179
237
|
|
|
180
238
|
/**
|
|
181
239
|
* Adds a checkbox for each suite and test for run selection.
|
|
182
240
|
*/
|
|
183
241
|
|
|
184
|
-
|
|
242
|
+
const addGrepButtons = () => {
|
|
185
243
|
const hasStyles = window.top?.document.querySelector('#grepButtonsStyle');
|
|
186
244
|
|
|
187
245
|
const grepTestsBtnClass = 'grep-tests-btn';
|
|
188
246
|
|
|
189
247
|
const defaultStyles = `
|
|
190
248
|
.grep-tests-btn {
|
|
249
|
+
pointer-events: auto;
|
|
191
250
|
background: none;
|
|
192
251
|
color: inherit;
|
|
193
252
|
padding: 0 20px;
|
|
@@ -207,9 +266,16 @@ export const addGrepButtons = () => {
|
|
|
207
266
|
runnablesStyleEl.innerHTML = defaultStyles;
|
|
208
267
|
runnablesEl?.appendChild(runnablesStyleEl);
|
|
209
268
|
}
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
269
|
+
let testsAndSuites;
|
|
270
|
+
if (Cypress.version >= '15.0.0') {
|
|
271
|
+
// TODO: Cypress v15 implemented a new suite naming convention that utilizes " > " separator between nested suites
|
|
272
|
+
// For now, only allowing tests to be selected for simplicity
|
|
273
|
+
testsAndSuites = window.top?.document.querySelectorAll('.test.runnable');
|
|
274
|
+
} else {
|
|
275
|
+
testsAndSuites = window.top?.document.querySelectorAll(
|
|
276
|
+
'.test.runnable, .suite.runnable'
|
|
277
|
+
);
|
|
278
|
+
}
|
|
213
279
|
[...testsAndSuites].forEach((t) => {
|
|
214
280
|
const header = t.querySelector('.collapsible-header');
|
|
215
281
|
const title = header.querySelector('.runnable-title');
|
|
@@ -259,52 +325,143 @@ export const addGrepButtons = () => {
|
|
|
259
325
|
|
|
260
326
|
// To prevent a checkbox from expanding a runnable, click the collapsible
|
|
261
327
|
grepTestsBtn?.addEventListener('change', (e) => {
|
|
262
|
-
if (e.target.checked) {
|
|
328
|
+
if (e.target.checked || e.target.unchecked) {
|
|
263
329
|
header.click();
|
|
264
330
|
}
|
|
265
331
|
});
|
|
266
332
|
});
|
|
267
333
|
};
|
|
268
334
|
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
Cypress.on('window:unload', () => {
|
|
273
|
-
// Store the current Cypress test runner url
|
|
274
|
-
// This is to check against any spec change in test runner while the grep filter is activated
|
|
275
|
-
// If a user does switch spec while filter is active, the filter will be reset
|
|
276
|
-
const sidebarSpecLinkPage = window.top?.document.querySelector(
|
|
277
|
-
'[data-cy="sidebar-link-specs-page"]'
|
|
278
|
-
);
|
|
279
|
-
const grepTestToggleElement =
|
|
280
|
-
window.top?.document.querySelector('#grepTestToggle');
|
|
335
|
+
/**
|
|
336
|
+
* Adds a clickable test tag for each respective test in Cypress open mode.
|
|
337
|
+
*/
|
|
281
338
|
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
339
|
+
export const addTags = () => {
|
|
340
|
+
const defaultStyles = `
|
|
341
|
+
[data-attribute="test-tags"]:focus {
|
|
342
|
+
box-shadow: 0 0 0 3px rgba(96, 165, 250, 0.9);;
|
|
343
|
+
outline: none;
|
|
344
|
+
}
|
|
345
|
+
`;
|
|
346
|
+
if (Cypress.env('specTags')) {
|
|
347
|
+
const hasStyles = window.top?.document.querySelector('#tagPillStyle');
|
|
348
|
+
|
|
349
|
+
if (!hasStyles) {
|
|
350
|
+
const runnablesStyleEl = window.top?.document.createElement('style');
|
|
351
|
+
const runnables = window.top?.document.querySelector('.runnables');
|
|
352
|
+
runnablesStyleEl.setAttribute('id', 'tagPillStyle');
|
|
353
|
+
runnablesStyleEl.innerHTML = defaultStyles;
|
|
354
|
+
runnables?.appendChild(runnablesStyleEl);
|
|
288
355
|
}
|
|
289
356
|
|
|
290
|
-
|
|
291
|
-
|
|
357
|
+
const testsAndSuites =
|
|
358
|
+
window.top?.document.querySelectorAll('.test.runnable');
|
|
359
|
+
[...testsAndSuites].forEach((t) => {
|
|
360
|
+
const header = t.querySelector('.collapsible-header');
|
|
361
|
+
const collapsibleHeaderText = header?.querySelector(
|
|
362
|
+
'.collapsible-header-text'
|
|
363
|
+
);
|
|
364
|
+
if (!collapsibleHeaderText.className.includes('flex flex-wrap gap-2')) {
|
|
365
|
+
collapsibleHeaderText.className += ' flex flex-wrap gap-2';
|
|
366
|
+
}
|
|
367
|
+
const title = header.querySelector('.runnable-title');
|
|
368
|
+
const testName = title.innerText.split('\n')[0];
|
|
369
|
+
const allSpecTags = Cypress.env('specTags');
|
|
370
|
+
const testTag = getTagsForTitle(testName, allSpecTags);
|
|
371
|
+
if (t.querySelectorAll('[data-attribute="test-tags"]').length === 0) {
|
|
372
|
+
renderTagPills(testTag, title);
|
|
373
|
+
}
|
|
374
|
+
});
|
|
375
|
+
}
|
|
376
|
+
};
|
|
377
|
+
|
|
378
|
+
function getTagsForTitle(title, fullTagsObj) {
|
|
379
|
+
const test = fullTagsObj[title];
|
|
380
|
+
if (!test) {
|
|
381
|
+
return []; // Title not found
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
return [...test.effectiveTestTags, ...test.requiredTestTags];
|
|
292
385
|
}
|
|
293
386
|
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
387
|
+
function renderTagPills(tags, container) {
|
|
388
|
+
tags.forEach((tag) => {
|
|
389
|
+
const pill = document.createElement('button');
|
|
390
|
+
pill.textContent = tag;
|
|
391
|
+
pill.setAttribute('type', 'button');
|
|
392
|
+
pill.setAttribute('aria-label', 'Filter by test tag from grep plugin');
|
|
393
|
+
pill.setAttribute('data-attribute', 'test-tags');
|
|
394
|
+
|
|
395
|
+
const brightColors = [
|
|
396
|
+
'#FF7373', // Red
|
|
397
|
+
'#FFB673', // Orange
|
|
398
|
+
'#FFE673', // Yellow
|
|
399
|
+
'#CFFF73', // Lime
|
|
400
|
+
'#73FF78', // Light Green
|
|
401
|
+
'#73FFC6', // Aqua
|
|
402
|
+
'#73E6FF', // Sky Blue
|
|
403
|
+
'#73A6FF', // Blue
|
|
404
|
+
'#7373FF', // Indigo
|
|
405
|
+
'#B473FF', // Purple
|
|
406
|
+
'#E673FF', // Magenta
|
|
407
|
+
'#FF73B6', // Rose
|
|
408
|
+
'#FF6E6E', // Slightly different Red
|
|
409
|
+
'#FFAB73', // Peach
|
|
410
|
+
'#FFF473', // Pale Yellow
|
|
411
|
+
'#DFFF73', // Pale Lime
|
|
412
|
+
'#73FFB6', // Mint
|
|
413
|
+
'#73DFFF', // Light Blue
|
|
414
|
+
'#A673FF', // Lavender
|
|
415
|
+
];
|
|
416
|
+
|
|
417
|
+
function tagNameToColor(str) {
|
|
418
|
+
let hash = 0;
|
|
419
|
+
for (let i = 0; i < str.length; i++)
|
|
420
|
+
hash = str.charCodeAt(i) + ((hash << 7) - hash);
|
|
421
|
+
return Math.abs(hash % 6);
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
function getTagColor(tag) {
|
|
425
|
+
const hash = tagNameToColor(tag);
|
|
426
|
+
return brightColors[hash % brightColors.length];
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
const bgColor = getTagColor(tag);
|
|
430
|
+
|
|
431
|
+
pill.setAttribute(
|
|
432
|
+
'style',
|
|
433
|
+
`
|
|
434
|
+
background: ${bgColor};
|
|
435
|
+
color: black;
|
|
436
|
+
padding: 0.1rem 0.2rem;
|
|
437
|
+
font-size: 0.875rem;
|
|
438
|
+
font-weight: bold;
|
|
439
|
+
border-radius: 2px;
|
|
440
|
+
display: inline-flex;
|
|
441
|
+
align-items: center;
|
|
442
|
+
white-space: nowrap;
|
|
443
|
+
cursor: pointer;
|
|
444
|
+
pointer-events: auto;
|
|
445
|
+
`
|
|
303
446
|
);
|
|
304
447
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
448
|
+
// Base styles
|
|
449
|
+
pill.className = `px-1 text-sm block inline-flex items-center whitespace-nowrap rounded`;
|
|
450
|
+
|
|
451
|
+
if (
|
|
452
|
+
// if the grep test toggle is checked, do not show checkboxes on each runnable
|
|
453
|
+
window.top?.document.querySelectorAll('#grepTestToggle:checked')
|
|
454
|
+
.length === 0
|
|
455
|
+
) {
|
|
456
|
+
// Handle selection toggle
|
|
457
|
+
pill.addEventListener('click', () => {
|
|
458
|
+
window.top?.document.querySelector('#grepTestToggle').click();
|
|
459
|
+
Cypress.grep(undefined, tag);
|
|
460
|
+
});
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
container.after(pill);
|
|
464
|
+
});
|
|
308
465
|
}
|
|
309
466
|
|
|
310
467
|
Cypress.on('test:before:run', () => {
|
|
@@ -317,22 +474,24 @@ Cypress.on('test:before:run', () => {
|
|
|
317
474
|
}
|
|
318
475
|
});
|
|
319
476
|
|
|
320
|
-
// To account for when the collapsible runnables are removed, add back grep buttons
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
window.top?.document.querySelectorAll('#grepTestToggle:checked').length === 0
|
|
324
|
-
) {
|
|
325
|
-
// watching for changes to DOM structure
|
|
326
|
-
MutationObserver = window.MutationObserver;
|
|
477
|
+
// To account for when the collapsible runnables are removed, add back tags and grep buttons
|
|
478
|
+
// watching for changes to DOM structure
|
|
479
|
+
MutationObserver = window.MutationObserver;
|
|
327
480
|
|
|
328
|
-
|
|
481
|
+
var observer = new MutationObserver(function () {
|
|
482
|
+
if (
|
|
483
|
+
// if the grep test toggle is checked, do not show checkboxes on each runnable
|
|
484
|
+
window.top?.document.querySelectorAll('#grepTestToggle:checked').length ===
|
|
485
|
+
0
|
|
486
|
+
) {
|
|
329
487
|
// fired when a mutation occurs
|
|
330
488
|
addGrepButtons();
|
|
331
|
-
}
|
|
489
|
+
}
|
|
490
|
+
addTags();
|
|
491
|
+
});
|
|
332
492
|
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
}
|
|
493
|
+
// defining the window.top?.document to be observed by the observer
|
|
494
|
+
observer.observe(window.top?.document, {
|
|
495
|
+
subtree: true,
|
|
496
|
+
attributes: true,
|
|
497
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cypress-plugin-grep-boxes",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "Cypress plugin that allows user to run specific tests in open mode.",
|
|
5
5
|
"main": "./index.js",
|
|
6
6
|
"keywords": [
|
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
"cypress-plugin"
|
|
10
10
|
],
|
|
11
11
|
"devDependencies": {
|
|
12
|
-
"@bahmutov/cy-grep": "^2.0
|
|
13
|
-
"cypress": "^
|
|
12
|
+
"@bahmutov/cy-grep": "^2.1.0",
|
|
13
|
+
"cypress": "^15.5.0"
|
|
14
14
|
},
|
|
15
15
|
"publishConfig": {
|
|
16
16
|
"registry": "https://registry.npmjs.org/"
|