cypress-plugin-grep-boxes 1.1.3 → 2.0.1

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 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
- ![Cypress-plugin-grep-boxes](./assets/cypress-plugin-grep-boxes-demo.gif)
9
+ ![cy-grep-boxes-demo](https://github.com/user-attachments/assets/5845963d-32a0-49a6-99be-3b81ca7d6f29)
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 { greppedTestToggle, addGrepButtons } from 'cypress-plugin-grep-boxes';
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,9 +68,13 @@ addGrepButtons();
64
68
 
65
69
  ## ✅ Open mode
66
70
 
67
- Within each spec, you can select any given number of suite(s) or individual test(s) and click the filter toggle located on the reporter above:
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
75
+
76
+ <img width="295" height="182" alt="grep-boxes-ui" src="https://github.com/user-attachments/assets/fad9ebc9-e417-41aa-9f31-519855113d17" />
68
77
 
69
- ![Cypress grep-boxes within UI mode](./assets/grep-boxes-ui.png)
70
78
 
71
79
  ### Use Required Test Tags Instead Of Skipping Tests
72
80
 
@@ -97,7 +105,8 @@ Cypress Test Runner UI automatically runs available tests once a spec file is op
97
105
 
98
106
  To prevent this behavior to have control of when and which tests to run, add the environment variable `disableInitialAutoRun=true`:
99
107
 
100
- ![disableInitialAutoRun Demo](./assets/disableInitialAutoRun_demo.gif)
108
+ ![disableInitialAutoRun_demo](https://github.com/user-attachments/assets/95fc4807-847b-432e-9b03-dc4fbe9f955a)
109
+
101
110
 
102
111
  ```bash
103
112
  # Example via CLI
@@ -10,12 +10,16 @@ context('Window', () => {
10
10
  cy.window().should('have.property', 'top');
11
11
  });
12
12
 
13
- it('cy.document() - get the document object', () => {
14
- // https://on.cypress.io/document
15
- cy.document().should('have.property', 'charset').and('eq', 'UTF-8');
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
  });
@@ -15,12 +15,10 @@
15
15
 
16
16
  // Import commands.js using ES2015 syntax:
17
17
  import './commands';
18
- import { greppedTestToggle, addGrepButtons } from '../../index';
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
- export const greppedTestToggle = () => {
9
- registerCypressGrep();
10
- const hasStyles = window.top?.document.querySelector('#grepTestToggleStyle');
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;
@@ -68,140 +65,181 @@ export const greppedTestToggle = () => {
68
65
  overflow: visible !important
69
66
  }
70
67
  `;
71
- 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">
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">
72
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"/>
73
70
  </svg>`;
74
71
 
75
- 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">
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">
76
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"/>
77
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"/>
78
75
  </svg>`;
79
76
 
80
- const turnOffgrepTestToggleDescription = 'Filter selected tests';
81
- const turnOngrepTestToggleDescription = 'Unfilter selected tests';
77
+ const turnOffgrepTestToggleDescription = 'Filter selected tests';
78
+ const turnOngrepTestToggleDescription = 'Unfilter selected tests';
82
79
 
83
- // append styles
84
- if (!hasStyles) {
85
- let reporterEl;
86
- const reporterStyleEl = document.createElement('style');
87
- if (Cypress.version >= '15.0.0') {
88
- reporterEl = window.top?.document.querySelector('.runnable-header');
89
- } else {
90
- reporterEl = window.top?.document.querySelector('#unified-reporter');
91
- }
92
- reporterStyleEl.setAttribute('id', 'grepTestToggleStyle');
93
- reporterStyleEl.innerHTML = defaultStyles;
94
- reporterEl?.appendChild(reporterStyleEl);
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');
95
88
  }
89
+ reporterStyleEl.setAttribute('id', 'grepTestToggleStyle');
90
+ reporterStyleEl.innerHTML = defaultStyles;
91
+ reporterEl?.appendChild(reporterStyleEl);
92
+ }
96
93
 
97
- if (!hasToggleButton) {
98
- let header;
99
- if (Cypress.version >= '15.0.0') {
100
- // TODO: Cypress v15 GUI provides option for Cypress Studio which pushes the grep toggle button around the UI
101
- // For simplicity, moving the toggle button to the spec container above the stop button
102
- header = window.top?.document.querySelector('.runnable-header');
103
- } else {
104
- header = window.top?.document.querySelector('#unified-reporter header');
105
- }
106
- const headerToggleDiv = document.createElement('div');
107
- const headerToggleSpan = document.createElement('span');
108
- const headerToggleTooltip = document.createElement('span');
109
- const headerToggleButton = document.createElement('button');
110
- const headerToggleInput = document.createElement('input');
111
- const headerToggleLabel = document.createElement('label');
112
-
113
- headerToggleInput.setAttribute('type', 'checkbox');
114
-
115
- headerToggleInput.setAttribute('id', 'grepTestToggle');
116
- headerToggleLabel.setAttribute('for', 'grepTestToggle');
117
- headerToggleLabel.setAttribute('id', 'grepTestToggleLabel');
118
- headerToggleLabel.innerHTML = turnOffgrepTestToggleIcon;
119
-
120
- headerToggleDiv.setAttribute('id', 'grepTestToggleControls');
121
- headerToggleTooltip.setAttribute('id', 'grepTestToggleTooltip');
122
- headerToggleTooltip.innerText = turnOffgrepTestToggleDescription;
123
- headerToggleButton.setAttribute(
124
- 'aria-label',
125
- turnOffgrepTestToggleDescription
126
- );
127
- headerToggleButton.setAttribute('id', 'grepTestToggleButton');
128
-
129
- headerToggleDiv.setAttribute('class', 'controls');
130
- header?.appendChild(headerToggleDiv);
131
- headerToggleDiv?.appendChild(headerToggleSpan);
132
- headerToggleDiv?.appendChild(headerToggleTooltip);
133
- headerToggleSpan?.appendChild(headerToggleButton);
134
- headerToggleButton?.appendChild(headerToggleInput);
135
- 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');
136
102
  }
137
-
138
- const grepTestToggleElement =
139
- window.top?.document.querySelector('#grepTestToggle');
140
- const grepTestToggleLabelElement = window.top?.document.querySelector(
141
- '[for=grepTestToggle]'
142
- );
143
- const grepTestToggleTooltipElement = window.top?.document.querySelector(
144
- '#grepTestToggleTooltip'
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
145
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
+ }
146
134
 
147
- grepTestToggleElement?.addEventListener('change', (e) => {
148
- const stopBtn = window.top?.document.querySelector('.reporter .stop');
149
-
150
- if (e.target.checked) {
151
- if (stopBtn) {
152
- stopBtn.click();
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
+ );
153
170
  }
154
- // store all checked checkbox values then send to grep in accepted format
155
- const tests = [
156
- ...window.top?.document.querySelectorAll('.grep-test-checkbox:checked'),
157
- ].map((e) => e.value);
158
- // store all non-checked checkbox values
159
- const uncheckedTests = [
160
- ...window.top?.document.querySelectorAll(
161
- '.grep-test-checkbox:not(:checked)'
162
- ),
163
- ].map((e) => e.value);
164
-
165
- tests.forEach((t) => {
166
- // if a checked test title begins with the grep inverted '-' symbol, remove the '-'
167
- if (t[0] === '-') {
168
- tests.push(t.slice(1));
169
- tests.splice(
170
- tests.findIndex((e) => e === t),
171
- 1
172
- );
173
- }
174
171
 
175
- // if a non-checked test's title includes a checked test's title, invert grep for unchecked title
176
- uncheckedTests.forEach((u) => {
177
- if (u.includes(t)) {
178
- tests.push(`-${u}`);
179
- }
180
- });
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}`);
176
+ }
181
177
  });
178
+ });
182
179
 
183
- Cypress.grep(tests.join(';'));
180
+ Cypress.grep(tests.join(';'));
184
181
 
185
- // when checked, grep only selected tests in spec
186
- grepTestToggleLabelElement.innerHTML = turnOngrepTestToggleIcon;
187
- grepTestToggleTooltipElement.innerHTML = turnOngrepTestToggleDescription;
188
- } else {
189
- if (stopBtn) {
190
- stopBtn.click();
191
- }
192
- // when unchecked, ungrep and show all tests in spec
193
- Cypress.grep();
194
- grepTestToggleLabelElement.innerHTML = turnOffgrepTestToggleIcon;
195
- grepTestToggleTooltipElement.innerHTML = turnOffgrepTestToggleDescription;
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();
196
216
  }
217
+
218
+ sidebarSpecLinkPage.setAttribute('data-url', window.top?.document.URL);
197
219
  });
198
- };
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
+ }
199
237
 
200
238
  /**
201
239
  * Adds a checkbox for each suite and test for run selection.
202
240
  */
203
241
 
204
- export const addGrepButtons = () => {
242
+ const addGrepButtons = () => {
205
243
  const hasStyles = window.top?.document.querySelector('#grepButtonsStyle');
206
244
 
207
245
  const grepTestsBtnClass = 'grep-tests-btn';
@@ -294,45 +332,136 @@ export const addGrepButtons = () => {
294
332
  });
295
333
  };
296
334
 
297
- // Wrapping logic within isInteractive check
298
- // This targets cypress open mode where user can switch specs
299
- if (Cypress.config('isInteractive')) {
300
- Cypress.on('window:unload', () => {
301
- // Store the current Cypress test runner url
302
- // This is to check against any spec change in test runner while the grep filter is activated
303
- // If a user does switch spec while filter is active, the filter will be reset
304
- const sidebarSpecLinkPage = window.top?.document.querySelector(
305
- '[data-cy="sidebar-link-specs-page"]'
306
- );
307
- const grepTestToggleElement =
308
- window.top?.document.querySelector('#grepTestToggle');
335
+ /**
336
+ * Adds a clickable test tag for each respective test in Cypress open mode.
337
+ */
309
338
 
310
- if (
311
- window.top?.document.URL !=
312
- sidebarSpecLinkPage.getAttribute('data-url') &&
313
- grepTestToggleElement.checked
314
- ) {
315
- grepTestToggleElement.click();
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);
316
355
  }
317
356
 
318
- sidebarSpecLinkPage.setAttribute('data-url', window.top?.document.URL);
319
- });
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];
320
385
  }
321
386
 
322
- if (Cypress.config('isInteractive')) {
323
- if (
324
- // if the grep test toggle is not checked, do not run tests
325
- Cypress.env('disableInitialAutoRun') &&
326
- window.top?.document.querySelectorAll('#grepTestToggle:checked').length ===
327
- 0
328
- ) {
329
- const sidebarSpecLinkPage = window.top?.document.querySelector(
330
- '[data-cy="sidebar-link-specs-page"]'
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
+ `
331
446
  );
332
447
 
333
- sidebarSpecLinkPage.setAttribute('data-url', window.top?.document.URL);
334
- Cypress.runner.stop();
335
- }
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
+ });
336
465
  }
337
466
 
338
467
  Cypress.on('test:before:run', () => {
@@ -345,22 +474,24 @@ Cypress.on('test:before:run', () => {
345
474
  }
346
475
  });
347
476
 
348
- // To account for when the collapsible runnables are removed, add back grep buttons
349
- if (
350
- // if the grep test toggle is checked, do not show checkboxes on each runnable
351
- window.top?.document.querySelectorAll('#grepTestToggle:checked').length === 0
352
- ) {
353
- // watching for changes to DOM structure
354
- 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;
355
480
 
356
- var observer = new MutationObserver(function () {
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
+ ) {
357
487
  // fired when a mutation occurs
358
488
  addGrepButtons();
359
- });
489
+ }
490
+ addTags();
491
+ });
360
492
 
361
- // defining the window.top?.document to be observed by the observer
362
- observer.observe(window.top?.document, {
363
- subtree: true,
364
- attributes: true,
365
- });
366
- }
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": "1.1.3",
3
+ "version": "2.0.1",
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.37",
13
- "cypress": "^15.4.0"
12
+ "@bahmutov/cy-grep": "^2.1.0",
13
+ "cypress": "^15.5.0"
14
14
  },
15
15
  "publishConfig": {
16
16
  "registry": "https://registry.npmjs.org/"
Binary file