@gitlab/ui 80.13.0 → 80.13.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/CHANGELOG.md CHANGED
@@ -1,3 +1,10 @@
1
+ ## [80.13.1](https://gitlab.com/gitlab-org/gitlab-ui/compare/v80.13.0...v80.13.1) (2024-05-24)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * **GlFilteredSearch:** set initial state when value is updated to empty array ([19eb8fa](https://gitlab.com/gitlab-org/gitlab-ui/commit/19eb8fa4fe075597a6b938d1f8f019ae9a10e70b))
7
+
1
8
  # [80.13.0](https://gitlab.com/gitlab-org/gitlab-ui/compare/v80.12.0...v80.13.0) (2024-05-22)
2
9
 
3
10
 
@@ -226,8 +226,9 @@ var script = {
226
226
  },
227
227
  value: {
228
228
  handler(newValue, oldValue) {
229
- if (newValue.length && !isEqual(newValue, oldValue)) {
230
- this.applyNewValue(cloneDeep(newValue));
229
+ if (!isEqual(newValue, oldValue)) {
230
+ const value = newValue.length ? newValue : initialState();
231
+ this.applyNewValue(cloneDeep(value));
231
232
  }
232
233
  },
233
234
  deep: true,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gitlab/ui",
3
- "version": "80.13.0",
3
+ "version": "80.13.1",
4
4
  "description": "GitLab UI Components",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",
@@ -39,7 +39,8 @@
39
39
  "storybook-static": "yarn storybook-prep && storybook build -c .storybook -o storybook",
40
40
  "pretest:unit": "yarn build-tokens",
41
41
  "test": "run-s test:unit test:visual",
42
- "test:integration": "NODE_ENV=test start-server-and-test start http://${STORYBOOK_HOST:-localhost}:9001/iframe.html 'yarn cy:run && yarn cy:edge && yarn cy:a11y'",
42
+ "test:integration": "yarn run test:integration:server 'yarn cy:run && yarn cy:edge && yarn cy:a11y'",
43
+ "test:integration:server": "NODE_ENV=test server-test http://${STORYBOOK_HOST:-localhost}:9001/iframe.html",
43
44
  "test:unit": "NODE_ENV=test jest",
44
45
  "test:unit:watch": "yarn test:unit --watch",
45
46
  "test:unit:debug": "NODE_ENV=test node --inspect node_modules/.bin/jest --testPathIgnorePatterns storyshot.spec.js --watch --runInBand",
@@ -103,6 +104,7 @@
103
104
  "@gitlab/fonts": "^1.3.0",
104
105
  "@gitlab/stylelint-config": "6.1.0",
105
106
  "@gitlab/svgs": "3.99.0",
107
+ "@jest/test-sequencer": "^29.7.0",
106
108
  "@rollup/plugin-commonjs": "^11.1.0",
107
109
  "@rollup/plugin-node-resolve": "^7.1.3",
108
110
  "@rollup/plugin-replace": "^2.3.2",
@@ -113,7 +115,7 @@
113
115
  "@storybook/addon-viewport": "^7.6.19",
114
116
  "@storybook/builder-webpack5": "^7.6.19",
115
117
  "@storybook/test": "^7.6.19",
116
- "@storybook/test-runner": "0.18.0",
118
+ "@storybook/test-runner": "0.18.1",
117
119
  "@storybook/theming": "^7.6.19",
118
120
  "@storybook/vue": "^7.6.17",
119
121
  "@storybook/vue-webpack5": "^7.6.17",
@@ -1,3 +1,4 @@
1
+ import { userEvent, within, waitFor, expect } from '@storybook/test';
1
2
  import GlFormGroup from '../form/form_group/form_group.vue';
2
3
  import { datepickerWidthOptionsMap } from '../../../utils/constants';
3
4
  import { disableControls } from '../../../utils/stories_utils';
@@ -29,9 +30,16 @@ export const Default = (_args, { argTypes }) => ({
29
30
  pickerValue: defaultDate,
30
31
  };
31
32
  },
32
- template: `<gl-datepicker :max-date="maxDate" :min-date="minDate" :start-opened="true" v-model="pickerValue" />`,
33
+ template: `<gl-datepicker :max-date="maxDate" :min-date="minDate" v-model="pickerValue" />`,
33
34
  });
34
35
  Default.args = generateProps();
36
+ Default.play = async ({ canvasElement }) => {
37
+ const canvas = within(canvasElement);
38
+ const button = canvas.getByRole('button', { name: 'Open datepicker' });
39
+ await userEvent.click(button);
40
+ await waitFor(() => expect(button).toHaveFocus());
41
+ await waitFor(() => expect(within(canvasElement).getByRole('grid')).toBeVisible());
42
+ };
35
43
 
36
44
  export const CustomTrigger = (_args, { argTypes }) => ({
37
45
  ...defaults,
@@ -888,4 +888,21 @@ describe('Filtered search integration tests', () => {
888
888
  { data: '' },
889
889
  ]);
890
890
  });
891
+
892
+ it('updates tokens list when empty value is passed dynamically', async () => {
893
+ mountComponent({ value: ['one'] });
894
+ await nextTick();
895
+
896
+ expect(wrapper.findAllComponents(GlFilteredSearchTerm)).toHaveLength(2);
897
+
898
+ await wrapper.setProps({
899
+ value: [],
900
+ });
901
+
902
+ const termComponents = wrapper.findAllComponents(GlFilteredSearchTerm).wrappers;
903
+ expect(termComponents).toHaveLength(1);
904
+ expect(termComponents.map((termComponent) => termComponent.props('value'))).toEqual([
905
+ { data: '' },
906
+ ]);
907
+ });
891
908
  });
@@ -237,8 +237,9 @@ export default {
237
237
  },
238
238
  value: {
239
239
  handler(newValue, oldValue) {
240
- if (newValue.length && !isEqual(newValue, oldValue)) {
241
- this.applyNewValue(cloneDeep(newValue));
240
+ if (!isEqual(newValue, oldValue)) {
241
+ const value = newValue.length ? newValue : initialState();
242
+ this.applyNewValue(cloneDeep(value));
242
243
  }
243
244
  },
244
245
  deep: true,
@@ -74,6 +74,7 @@ WithObjectValue.play = async ({ canvasElement }) => {
74
74
  await waitFor(() =>
75
75
  expect(within(document).getByRole('menuitem', { name: '1 giraffe' })).toBeVisible()
76
76
  );
77
+ await waitFor(() => expect(searchbox).toHaveFocus());
77
78
  };
78
79
 
79
80
  export const WithActions = (args, { argTypes }) => ({
@@ -99,6 +100,7 @@ WithActions.play = async ({ canvasElement }) => {
99
100
  await waitFor(() =>
100
101
  expect(within(document).getByRole('menuitem', { name: 'dog' })).toBeVisible()
101
102
  );
103
+ await waitFor(() => expect(searchbox).toHaveFocus());
102
104
  };
103
105
 
104
106
  export default {
@@ -1,9 +1,19 @@
1
+ import { userEvent, within, waitFor, expect } from '@storybook/test';
1
2
  import { GlModalDirective } from '../../../directives/modal';
2
3
  import GlButton from '../button/button.vue';
3
4
  import { variantOptionsWithNoDefault } from '../../../utils/constants';
4
5
  import GlModal from './modal.vue';
5
6
  import readme from './modal.md';
6
7
 
8
+ const play =
9
+ (expectFinalState = () => Promise.resolve()) =>
10
+ async ({ canvasElement }) => {
11
+ const canvas = within(canvasElement);
12
+ const button = canvas.getByRole('button');
13
+ await userEvent.click(button);
14
+ await expectFinalState();
15
+ };
16
+
7
17
  const generateTemplate = ({ props = {}, slots = {} } = {}) => {
8
18
  const extraProps = Object.entries(props)
9
19
  .map(([key, value]) => `:${key}="${value}"`)
@@ -27,7 +37,6 @@ const generateTemplate = ({ props = {}, slots = {} } = {}) => {
27
37
  :action-primary="{text: 'Okay'}"
28
38
  :action-secondary="{text: 'Discard Changes'}"
29
39
  :action-cancel="{text: 'Cancel'}"
30
- :visible="$options.viewMode !== 'docs'"
31
40
  :scrollable="scrollable"
32
41
  :no-focus-on-show="noFocusOnShow"
33
42
  modal-id="test-modal-id"
@@ -74,12 +83,26 @@ const generateProps = ({
74
83
 
75
84
  export const Default = Template.bind({});
76
85
  Default.args = generateProps();
86
+ Default.play = play(() =>
87
+ waitFor(() =>
88
+ expect(
89
+ within(within(document).getByRole('dialog')).getByRole('button', { name: 'Cancel' })
90
+ ).toHaveFocus()
91
+ )
92
+ );
77
93
 
78
94
  export const WithScrollingContent = Template.bind({});
79
95
  WithScrollingContent.args = generateProps({
80
96
  contentPagraphs: 100,
81
97
  scrollable: true,
82
98
  });
99
+ WithScrollingContent.play = play(() =>
100
+ waitFor(() =>
101
+ expect(
102
+ within(within(document).getByRole('dialog')).getByRole('button', { name: 'Cancel' })
103
+ ).toHaveFocus()
104
+ )
105
+ );
83
106
 
84
107
  export const WithAHeader = (args, { argTypes, viewMode }) => ({
85
108
  components: { GlModal, GlButton },
@@ -93,6 +116,13 @@ export const WithAHeader = (args, { argTypes, viewMode }) => ({
93
116
  viewMode,
94
117
  });
95
118
  WithAHeader.args = generateProps();
119
+ WithAHeader.play = play(() =>
120
+ waitFor(() =>
121
+ expect(
122
+ within(within(document).getByRole('dialog')).getByRole('button', { name: 'Cancel' })
123
+ ).toHaveFocus()
124
+ )
125
+ );
96
126
 
97
127
  export const WithoutAFooter = (args, { argTypes, viewMode }) => ({
98
128
  components: { GlModal, GlButton },
@@ -104,11 +134,19 @@ export const WithoutAFooter = (args, { argTypes, viewMode }) => ({
104
134
  viewMode,
105
135
  });
106
136
  WithoutAFooter.args = generateProps();
137
+ WithoutAFooter.play = play(() =>
138
+ waitFor(() =>
139
+ expect(
140
+ within(within(document).getByRole('dialog')).getByRole('button', { name: 'Close' })
141
+ ).toHaveFocus()
142
+ )
143
+ );
107
144
 
108
145
  export const WithoutFocus = Template.bind({});
109
146
  WithoutFocus.args = generateProps({
110
147
  noFocusOnShow: true,
111
148
  });
149
+ WithoutFocus.play = play();
112
150
 
113
151
  export default {
114
152
  title: 'base/modal',
@@ -12,6 +12,7 @@ const play = async ({ canvasElement }) => {
12
12
  const canvas = within(canvasElement);
13
13
  const button = canvas.getByRole('button');
14
14
  await userEvent.click(button);
15
+ await waitFor(() => expect(within(canvasElement).getByRole('button')).toHaveFocus());
15
16
  await waitFor(() => expect(within(document).getByRole('status')).toBeVisible());
16
17
  };
17
18
 
@@ -27,6 +27,7 @@ const play = async ({ canvasElement }) => {
27
27
  const canvas = within(canvasElement);
28
28
  const button = canvas.getByRole('button');
29
29
  await userEvent.click(button);
30
+ await waitFor(() => expect(button).toHaveFocus());
30
31
  await waitFor(() => expect(within(document).getByRole('tooltip')).toBeVisible());
31
32
  };
32
33