@gitlab/ui 78.17.0 → 78.19.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 CHANGED
@@ -1,3 +1,17 @@
1
+ # [78.19.0](https://gitlab.com/gitlab-org/gitlab-ui/compare/v78.18.0...v78.19.0) (2024-04-22)
2
+
3
+
4
+ ### Features
5
+
6
+ * **GlFormTextarea:** add support for character count ([1b359aa](https://gitlab.com/gitlab-org/gitlab-ui/commit/1b359aabb514831bddaeca108132427ecde4ae64))
7
+
8
+ # [78.18.0](https://gitlab.com/gitlab-org/gitlab-ui/compare/v78.17.0...v78.18.0) (2024-04-19)
9
+
10
+
11
+ ### Features
12
+
13
+ * **GlDisclosureDropdown:** Reorder dropdown items in example ([7145be6](https://gitlab.com/gitlab-org/gitlab-ui/commit/7145be686e16ae286e1189071a15e58403aaa635))
14
+
1
15
  # [78.17.0](https://gitlab.com/gitlab-org/gitlab-ui/compare/v78.16.0...v78.17.0) (2024-04-19)
2
16
 
3
17
 
@@ -1,4 +1,6 @@
1
1
  import { BFormTextarea } from 'bootstrap-vue/esm/index.js';
2
+ import debounce from 'lodash/debounce';
3
+ import uniqueId from 'lodash/uniqueId';
2
4
  import __vue_normalize__ from 'vue-runtime-helpers/dist/normalize-component.js';
3
5
 
4
6
  const model = {
@@ -29,8 +31,23 @@ var script = {
29
31
  type: Boolean,
30
32
  required: false,
31
33
  default: false
34
+ },
35
+ /**
36
+ * Max character count for the textarea.
37
+ */
38
+ characterCount: {
39
+ type: Number,
40
+ required: false,
41
+ default: null
32
42
  }
33
43
  },
44
+ data() {
45
+ return {
46
+ characterCountId: uniqueId('form-textarea-character-count-'),
47
+ remainingCharacterCount: this.initialRemainingCharacterCount(),
48
+ remainingCharacterCountSrOnly: this.initialRemainingCharacterCount()
49
+ };
50
+ },
34
51
  computed: {
35
52
  listeners() {
36
53
  var _this = this;
@@ -62,13 +79,50 @@ var script = {
62
79
  },
63
80
  keypressEvent() {
64
81
  return this.submitOnEnter ? 'keyup' : null;
82
+ },
83
+ isCharacterCountOverLimit() {
84
+ return this.remainingCharacterCount < 0;
85
+ },
86
+ characterCountTextClass() {
87
+ return this.isCharacterCountOverLimit ? 'gl-text-red-500' : 'gl-text-gray-500';
88
+ },
89
+ showCharacterCount() {
90
+ return this.characterCount !== null;
91
+ },
92
+ bFormTextareaProps() {
93
+ return {
94
+ ...this.$attrs,
95
+ class: 'gl-form-input gl-form-textarea',
96
+ noResize: this.noResize,
97
+ value: this.value
98
+ };
99
+ }
100
+ },
101
+ watch: {
102
+ value(newValue) {
103
+ if (!this.showCharacterCount) {
104
+ return;
105
+ }
106
+ this.remainingCharacterCount = this.characterCount - newValue.length;
107
+ this.debouncedUpdateRemainingCharacterCountSrOnly(newValue);
65
108
  }
66
109
  },
110
+ created() {
111
+ // Debounce updating the remaining character count for a second so
112
+ // screen readers announce the remaining text after the text in the textarea.
113
+ this.debouncedUpdateRemainingCharacterCountSrOnly = debounce(this.updateRemainingCharacterCountSrOnly, 1000);
114
+ },
67
115
  methods: {
68
116
  handleKeyPress(e) {
69
117
  if (e.keyCode === 13 && (e.metaKey || e.ctrlKey)) {
70
118
  this.$emit('submit');
71
119
  }
120
+ },
121
+ updateRemainingCharacterCountSrOnly(newValue) {
122
+ this.remainingCharacterCountSrOnly = this.characterCount - newValue.length;
123
+ },
124
+ initialRemainingCharacterCount() {
125
+ return this.characterCount - this.value.length;
72
126
  }
73
127
  }
74
128
  };
@@ -77,7 +131,7 @@ var script = {
77
131
  const __vue_script__ = script;
78
132
 
79
133
  /* template */
80
- var __vue_render__ = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('b-form-textarea',_vm._g(_vm._b({staticClass:"gl-form-input gl-form-textarea",attrs:{"no-resize":_vm.noResize,"value":_vm.value},nativeOn:_vm._d({},[_vm.keypressEvent,function($event){return _vm.handleKeyPress.apply(null, arguments)}])},'b-form-textarea',_vm.$attrs,false),_vm.listeners))};
134
+ var __vue_render__ = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return (_vm.showCharacterCount)?_c('div',[_c('b-form-textarea',_vm._g(_vm._b({attrs:{"aria-describedby":_vm.characterCountId},nativeOn:_vm._d({},[_vm.keypressEvent,function($event){return _vm.handleKeyPress.apply(null, arguments)}])},'b-form-textarea',_vm.bFormTextareaProps,false),_vm.listeners)),_vm._v(" "),_c('small',{class:['form-text', _vm.characterCountTextClass],attrs:{"aria-hidden":"true"}},[(_vm.isCharacterCountOverLimit)?_vm._t("character-count-over-limit-text",null,{"count":Math.abs(_vm.remainingCharacterCount)}):_vm._t("character-count-text",null,{"count":_vm.remainingCharacterCount})],2),_vm._v(" "),_c('div',{staticClass:"gl-sr-only",attrs:{"id":_vm.characterCountId,"aria-live":"polite","data-testid":"character-count-text-sr-only"}},[(_vm.isCharacterCountOverLimit)?_vm._t("character-count-over-limit-text",null,{"count":Math.abs(_vm.remainingCharacterCount)}):_vm._t("character-count-text",null,{"count":_vm.remainingCharacterCountSrOnly})],2)],1):_c('b-form-textarea',_vm._g(_vm._b({nativeOn:_vm._d({},[_vm.keypressEvent,function($event){return _vm.handleKeyPress.apply(null, arguments)}])},'b-form-textarea',_vm.bFormTextareaProps,false),_vm.listeners))};
81
135
  var __vue_staticRenderFns__ = [];
82
136
 
83
137
  /* style */
@@ -6,17 +6,6 @@ const mockItems = [{
6
6
  rel: 'nofollow',
7
7
  'data-method': 'put'
8
8
  }
9
- }, {
10
- text: 'Close merge request',
11
- action: () => {
12
- // eslint-disable-next-line no-console
13
- console.log('CLOSED');
14
- },
15
- extraAttrs: {
16
- class: 'gl-text-red-500!',
17
- rel: 'nofollow',
18
- 'data-method': 'put'
19
- }
20
9
  }, {
21
10
  text: 'Create new',
22
11
  href: 'https://gitlab.com/gitlab-org/gitlab/-/merge_requests/new',
@@ -30,6 +19,17 @@ const mockItems = [{
30
19
  extraAttrs: {
31
20
  'data-uuid': '1234'
32
21
  }
22
+ }, {
23
+ text: 'Close merge request',
24
+ action: () => {
25
+ // eslint-disable-next-line no-console
26
+ console.log('CLOSED');
27
+ },
28
+ extraAttrs: {
29
+ class: 'gl-text-red-500!',
30
+ rel: 'nofollow',
31
+ 'data-method': 'put'
32
+ }
33
33
  }];
34
34
  const mockItemsCustomItem = [{
35
35
  text: 'Assigned to you',
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Do not edit directly
3
- * Generated on Fri, 19 Apr 2024 15:34:12 GMT
3
+ * Generated on Mon, 22 Apr 2024 11:22:17 GMT
4
4
  */
5
5
 
6
6
  :root {
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Do not edit directly
3
- * Generated on Fri, 19 Apr 2024 15:34:12 GMT
3
+ * Generated on Mon, 22 Apr 2024 11:22:17 GMT
4
4
  */
5
5
 
6
6
  :root.gl-dark {
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Do not edit directly
3
- * Generated on Fri, 19 Apr 2024 15:34:12 GMT
3
+ * Generated on Mon, 22 Apr 2024 11:22:17 GMT
4
4
  */
5
5
 
6
6
  export const DATA_VIZ_GREEN_50 = "#133a03";
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Do not edit directly
3
- * Generated on Fri, 19 Apr 2024 15:34:12 GMT
3
+ * Generated on Mon, 22 Apr 2024 11:22:17 GMT
4
4
  */
5
5
 
6
6
  export const DATA_VIZ_GREEN_50 = "#ddfab7";
@@ -1,6 +1,6 @@
1
1
 
2
2
  // Do not edit directly
3
- // Generated on Fri, 19 Apr 2024 15:34:12 GMT
3
+ // Generated on Mon, 22 Apr 2024 11:22:17 GMT
4
4
 
5
5
  $gl-text-tertiary: #737278 !default;
6
6
  $gl-text-secondary: #89888d !default;
@@ -1,6 +1,6 @@
1
1
 
2
2
  // Do not edit directly
3
- // Generated on Fri, 19 Apr 2024 15:34:12 GMT
3
+ // Generated on Mon, 22 Apr 2024 11:22:17 GMT
4
4
 
5
5
  $gl-text-tertiary: #89888d !default;
6
6
  $gl-text-secondary: #737278 !default;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gitlab/ui",
3
- "version": "78.17.0",
3
+ "version": "78.19.0",
4
4
  "description": "GitLab UI Components",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",
@@ -131,14 +131,14 @@
131
131
  "babel-jest": "29.0.1",
132
132
  "babel-loader": "^8.0.5",
133
133
  "bootstrap": "4.6.2",
134
- "cypress": "13.7.3",
134
+ "cypress": "13.8.0",
135
135
  "cypress-axe": "^1.4.0",
136
136
  "cypress-real-events": "^1.11.0",
137
137
  "dompurify": "^3.0.0",
138
138
  "emoji-regex": "^10.0.0",
139
139
  "eslint": "8.57.0",
140
140
  "eslint-import-resolver-jest": "3.0.2",
141
- "eslint-plugin-cypress": "2.15.1",
141
+ "eslint-plugin-cypress": "2.15.2",
142
142
  "eslint-plugin-storybook": "0.8.0",
143
143
  "glob": "10.3.3",
144
144
  "identity-obj-proxy": "^3.0.0",
@@ -1,6 +1,9 @@
1
1
  import { mount } from '@vue/test-utils';
2
+ import lodashDebounce from 'lodash/debounce';
2
3
  import GlFormTextarea from './form_textarea.vue';
3
4
 
5
+ jest.mock('lodash/debounce', () => jest.fn((fn) => fn));
6
+
4
7
  const modelEvent = GlFormTextarea.model.event;
5
8
  const newValue = 'foo';
6
9
 
@@ -10,6 +13,25 @@ describe('GlFormTextArea', () => {
10
13
  const createComponent = (propsData = {}) => {
11
14
  wrapper = mount(GlFormTextarea, {
12
15
  propsData,
16
+ scopedSlots: {
17
+ 'character-count-text': function characterCountText({ count }) {
18
+ return count === 1 ? `${count} character remaining` : `${count} characters remaining`;
19
+ },
20
+ 'character-count-over-limit-text': function characterCountOverLimitText({ count }) {
21
+ return count === 1 ? `${count} character over limit` : `${count} characters over limit`;
22
+ },
23
+ },
24
+ });
25
+ };
26
+
27
+ const findTextarea = () => wrapper.find('textarea');
28
+
29
+ const itUpdatesDebouncedScreenReaderText = (expectedText) => {
30
+ it('updates debounced screen reader text', () => {
31
+ expect(lodashDebounce).toHaveBeenCalledWith(expect.any(Function), 1000);
32
+ expect(wrapper.find('[data-testid="character-count-text-sr-only"]').text()).toBe(
33
+ expectedText
34
+ );
13
35
  });
14
36
  };
15
37
 
@@ -20,7 +42,7 @@ describe('GlFormTextArea', () => {
20
42
  });
21
43
 
22
44
  it(`sets the textarea's value`, () => {
23
- expect(wrapper.element.value).toBe('initial');
45
+ expect(findTextarea().element.value).toBe('initial');
24
46
  });
25
47
 
26
48
  describe('when the value prop changes', () => {
@@ -30,7 +52,7 @@ describe('GlFormTextArea', () => {
30
52
  });
31
53
 
32
54
  it(`updates the textarea's value`, () => {
33
- expect(wrapper.element.value).toBe(newValue);
55
+ expect(findTextarea().element.value).toBe(newValue);
34
56
  });
35
57
  });
36
58
  });
@@ -39,7 +61,7 @@ describe('GlFormTextArea', () => {
39
61
  beforeEach(() => {
40
62
  createComponent();
41
63
 
42
- wrapper.setValue(newValue);
64
+ findTextarea().setValue(newValue);
43
65
  });
44
66
 
45
67
  it('synchronously emits update event', () => {
@@ -59,7 +81,7 @@ describe('GlFormTextArea', () => {
59
81
 
60
82
  createComponent({ debounce });
61
83
 
62
- wrapper.setValue(newValue);
84
+ findTextarea().setValue(newValue);
63
85
  });
64
86
 
65
87
  it('synchronously emits an update event', () => {
@@ -82,7 +104,7 @@ describe('GlFormTextArea', () => {
82
104
  beforeEach(() => {
83
105
  createComponent({ lazy: true });
84
106
 
85
- wrapper.setValue(newValue);
107
+ findTextarea().setValue(newValue);
86
108
  });
87
109
 
88
110
  it('synchronously emits an update event', () => {
@@ -119,4 +141,65 @@ describe('GlFormTextArea', () => {
119
141
  expect(wrapper.emitted('submit')).toEqual([[]]);
120
142
  });
121
143
  });
144
+
145
+ describe('when `characterCount` prop is set', () => {
146
+ const characterCount = 10;
147
+
148
+ describe('when textarea character count is under the max character count', () => {
149
+ const textareaCharacterCount = 5;
150
+ const expectedText = `${characterCount - textareaCharacterCount} characters remaining`;
151
+
152
+ beforeEach(() => {
153
+ createComponent({
154
+ value: 'a'.repeat(textareaCharacterCount),
155
+ characterCount,
156
+ });
157
+ });
158
+
159
+ it('displays remaining characters', () => {
160
+ expect(wrapper.text()).toContain(expectedText);
161
+ });
162
+
163
+ itUpdatesDebouncedScreenReaderText(expectedText);
164
+ });
165
+
166
+ describe('when textarea character count is over the max character count', () => {
167
+ const textareaCharacterCount = 15;
168
+ const expectedText = `${textareaCharacterCount - characterCount} characters over limit`;
169
+
170
+ beforeEach(() => {
171
+ createComponent({
172
+ value: 'a'.repeat(textareaCharacterCount),
173
+ characterCount,
174
+ });
175
+ });
176
+
177
+ it('displays number of characters over', () => {
178
+ expect(wrapper.text()).toContain(expectedText);
179
+ });
180
+
181
+ itUpdatesDebouncedScreenReaderText(expectedText);
182
+ });
183
+
184
+ describe('when textarea value is updated', () => {
185
+ const textareaCharacterCount = 5;
186
+ const newTextareaCharacterCount = textareaCharacterCount + 3;
187
+ const expectedText = `${characterCount - newTextareaCharacterCount} characters remaining`;
188
+
189
+ beforeEach(() => {
190
+ createComponent({
191
+ value: 'a'.repeat(textareaCharacterCount),
192
+ characterCount,
193
+ });
194
+
195
+ wrapper.setProps({ value: 'a'.repeat(newTextareaCharacterCount) });
196
+ });
197
+
198
+ it('updates character count text', () => {
199
+ expect(wrapper.text()).toContain(expectedText);
200
+ });
201
+
202
+ itUpdatesDebouncedScreenReaderText(expectedText);
203
+ });
204
+ });
122
205
  });
@@ -3,32 +3,57 @@ import readme from './form_textarea.md';
3
3
 
4
4
  const template = `
5
5
  <gl-form-textarea
6
- v-model="model"
6
+ :value="value"
7
7
  :placeholder="placeholder"
8
8
  :rows="5"
9
9
  :no-resize="noResize"
10
- />
10
+ :character-count="characterCount"
11
+ @input="onInput"
12
+ >
13
+ <template #character-count-text="{ count }">{{ characterCountText(count) }}</template>
14
+ <template #character-count-over-limit-text="{ count }">{{ characterCountOverLimitText(count) }}</template>
15
+ </gl-form-textarea>
11
16
  `;
12
17
 
13
18
  const generateProps = ({
14
- model = 'We take inspiration from other companies, and we always go for the boring solutions. Just like the rest of our work, we continually adjust our values and strive always to make them better. We used to have more values, but it was difficult to remember them all, so we condensed them and gave sub-values and created an acronym. Everyone is welcome to suggest improvements.',
19
+ value = 'We take inspiration from other companies, and we always go for the boring solutions. Just like the rest of our work, we continually adjust our values and strive always to make them better. We used to have more values, but it was difficult to remember them all, so we condensed them and gave sub-values and created an acronym. Everyone is welcome to suggest improvements.',
15
20
  placeholder = 'hello',
16
21
  noResize = GlFormTextarea.props.noResize.default,
22
+ characterCount = null,
17
23
  } = {}) => ({
18
- model,
24
+ value,
19
25
  placeholder,
20
26
  noResize,
27
+ characterCount,
21
28
  });
22
29
 
23
- const Template = (args) => ({
30
+ const Template = (args, { updateArgs }) => ({
24
31
  components: { GlFormTextarea },
25
32
  props: Object.keys(args),
33
+ methods: {
34
+ onInput(value) {
35
+ updateArgs({ ...args, value });
36
+ },
37
+ characterCountText(count) {
38
+ return count === 1 ? `${count} character remaining` : `${count} characters remaining`;
39
+ },
40
+ characterCountOverLimitText(count) {
41
+ return count === 1 ? `${count} character over limit` : `${count} characters over limit`;
42
+ },
43
+ },
26
44
  template,
27
45
  });
28
46
 
29
47
  export const Default = Template.bind({});
30
48
  Default.args = generateProps();
31
49
 
50
+ export const WithCharacterCount = Template.bind({});
51
+ WithCharacterCount.args = generateProps({
52
+ value: '',
53
+ placeholder: 'hello',
54
+ characterCount: 100,
55
+ });
56
+
32
57
  export default {
33
58
  title: 'base/form/form-textarea',
34
59
  component: GlFormTextarea,
@@ -1,5 +1,7 @@
1
1
  <script>
2
2
  import { BFormTextarea } from 'bootstrap-vue';
3
+ import debounce from 'lodash/debounce';
4
+ import uniqueId from 'lodash/uniqueId';
3
5
 
4
6
  const model = {
5
7
  prop: 'value',
@@ -31,6 +33,21 @@ export default {
31
33
  required: false,
32
34
  default: false,
33
35
  },
36
+ /**
37
+ * Max character count for the textarea.
38
+ */
39
+ characterCount: {
40
+ type: Number,
41
+ required: false,
42
+ default: null,
43
+ },
44
+ },
45
+ data() {
46
+ return {
47
+ characterCountId: uniqueId('form-textarea-character-count-'),
48
+ remainingCharacterCount: this.initialRemainingCharacterCount(),
49
+ remainingCharacterCountSrOnly: this.initialRemainingCharacterCount(),
50
+ };
34
51
  },
35
52
  computed: {
36
53
  listeners() {
@@ -57,6 +74,41 @@ export default {
57
74
  keypressEvent() {
58
75
  return this.submitOnEnter ? 'keyup' : null;
59
76
  },
77
+ isCharacterCountOverLimit() {
78
+ return this.remainingCharacterCount < 0;
79
+ },
80
+ characterCountTextClass() {
81
+ return this.isCharacterCountOverLimit ? 'gl-text-red-500' : 'gl-text-gray-500';
82
+ },
83
+ showCharacterCount() {
84
+ return this.characterCount !== null;
85
+ },
86
+ bFormTextareaProps() {
87
+ return {
88
+ ...this.$attrs,
89
+ class: 'gl-form-input gl-form-textarea',
90
+ noResize: this.noResize,
91
+ value: this.value,
92
+ };
93
+ },
94
+ },
95
+ watch: {
96
+ value(newValue) {
97
+ if (!this.showCharacterCount) {
98
+ return;
99
+ }
100
+
101
+ this.remainingCharacterCount = this.characterCount - newValue.length;
102
+ this.debouncedUpdateRemainingCharacterCountSrOnly(newValue);
103
+ },
104
+ },
105
+ created() {
106
+ // Debounce updating the remaining character count for a second so
107
+ // screen readers announce the remaining text after the text in the textarea.
108
+ this.debouncedUpdateRemainingCharacterCountSrOnly = debounce(
109
+ this.updateRemainingCharacterCountSrOnly,
110
+ 1000
111
+ );
60
112
  },
61
113
  methods: {
62
114
  handleKeyPress(e) {
@@ -64,16 +116,59 @@ export default {
64
116
  this.$emit('submit');
65
117
  }
66
118
  },
119
+ updateRemainingCharacterCountSrOnly(newValue) {
120
+ this.remainingCharacterCountSrOnly = this.characterCount - newValue.length;
121
+ },
122
+ initialRemainingCharacterCount() {
123
+ return this.characterCount - this.value.length;
124
+ },
67
125
  },
68
126
  };
69
127
  </script>
70
128
 
71
129
  <template>
130
+ <div v-if="showCharacterCount">
131
+ <b-form-textarea
132
+ :aria-describedby="characterCountId"
133
+ v-bind="bFormTextareaProps"
134
+ v-on="listeners"
135
+ @[keypressEvent].native="handleKeyPress"
136
+ />
137
+ <small :class="['form-text', characterCountTextClass]" aria-hidden="true">
138
+ <!--
139
+ @slot Internationalized over character count text. Example: `<template #character-count-over-limit-text="{ count }">{{ n__('%d character over limit', '%d characters over limit', count) }}</template>`
140
+ @binding {number} count
141
+ -->
142
+ <slot
143
+ v-if="isCharacterCountOverLimit"
144
+ name="character-count-over-limit-text"
145
+ :count="Math.abs(remainingCharacterCount)"
146
+ ></slot>
147
+ <!--
148
+ @slot Internationalized character count text. Example: `<template #character-count-text="{ count }">{{ n__('%d character remaining', '%d characters remaining', count) }}</template>`
149
+ @binding {number} count
150
+ -->
151
+
152
+ <slot v-else name="character-count-text" :count="remainingCharacterCount"></slot>
153
+ </small>
154
+ <div
155
+ :id="characterCountId"
156
+ class="gl-sr-only"
157
+ aria-live="polite"
158
+ data-testid="character-count-text-sr-only"
159
+ >
160
+ <slot
161
+ v-if="isCharacterCountOverLimit"
162
+ name="character-count-over-limit-text"
163
+ :count="Math.abs(remainingCharacterCount)"
164
+ ></slot>
165
+
166
+ <slot v-else name="character-count-text" :count="remainingCharacterCountSrOnly"></slot>
167
+ </div>
168
+ </div>
72
169
  <b-form-textarea
73
- class="gl-form-input gl-form-textarea"
74
- :no-resize="noResize"
75
- v-bind="$attrs"
76
- :value="value"
170
+ v-else
171
+ v-bind="bFormTextareaProps"
77
172
  v-on="listeners"
78
173
  @[keypressEvent].native="handleKeyPress"
79
174
  />
@@ -51,7 +51,7 @@ describe('GlDisclosureDropdownItem', () => {
51
51
  describe.each`
52
52
  prop | mockItem
53
53
  ${'href'} | ${0}
54
- ${'to'} | ${3}
54
+ ${'to'} | ${2}
55
55
  `('when item has a `$prop`', ({ prop, mockItem }) => {
56
56
  const item = mockItems[mockItem];
57
57
 
@@ -102,7 +102,7 @@ describe('GlDisclosureDropdownItem', () => {
102
102
  });
103
103
 
104
104
  describe('when item has an `action`', () => {
105
- const item = mockItems[1];
105
+ const item = mockItems[3];
106
106
  const action = jest.spyOn(item, 'action');
107
107
 
108
108
  beforeEach(() => {
@@ -184,7 +184,7 @@ describe('GlDisclosureDropdownItem', () => {
184
184
  beforeEach(() => {
185
185
  buildWrapper({
186
186
  item: {
187
- ...mockItems[1],
187
+ ...mockItems[3],
188
188
  extraAttrs,
189
189
  },
190
190
  });
@@ -8,18 +8,6 @@ export const mockItems = [
8
8
  'data-method': 'put',
9
9
  },
10
10
  },
11
- {
12
- text: 'Close merge request',
13
- action: () => {
14
- // eslint-disable-next-line no-console
15
- console.log('CLOSED');
16
- },
17
- extraAttrs: {
18
- class: 'gl-text-red-500!',
19
- rel: 'nofollow',
20
- 'data-method': 'put',
21
- },
22
- },
23
11
  {
24
12
  text: 'Create new',
25
13
  href: 'https://gitlab.com/gitlab-org/gitlab/-/merge_requests/new',
@@ -35,6 +23,18 @@ export const mockItems = [
35
23
  'data-uuid': '1234',
36
24
  },
37
25
  },
26
+ {
27
+ text: 'Close merge request',
28
+ action: () => {
29
+ // eslint-disable-next-line no-console
30
+ console.log('CLOSED');
31
+ },
32
+ extraAttrs: {
33
+ class: 'gl-text-red-500!',
34
+ rel: 'nofollow',
35
+ 'data-method': 'put',
36
+ },
37
+ },
38
38
  ];
39
39
 
40
40
  export const mockItemsCustomItem = [