@rancher/shell 3.0.12-rc.4 → 3.0.12-rc.5
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/assets/styles/global/_button.scss +1 -1
- package/assets/translations/en-us.yaml +39 -10
- package/components/ActionDropdownShell.vue +5 -3
- package/components/ButtonGroup.vue +26 -1
- package/components/CruResource.vue +51 -2
- package/components/PromptRestore.vue +93 -32
- package/components/Questions/index.vue +1 -0
- package/components/ResourceTable.vue +1 -0
- package/components/SortableTable/index.vue +4 -3
- package/components/Wizard.vue +14 -1
- package/components/__tests__/ButtonGroup.test.ts +56 -0
- package/components/__tests__/PromptRestore.test.ts +169 -19
- package/components/fleet/GitRepoAdvancedTab.vue +1 -0
- package/components/fleet/GitRepoMetadataTab.vue +5 -0
- package/components/fleet/HelmOpAppCoConfigTab.vue +4 -0
- package/components/fleet/HelmOpMetadataTab.vue +5 -0
- package/components/form/FileSelector.vue +39 -1
- package/components/form/PrivateRegistry.constants.ts +7 -0
- package/components/form/PrivateRegistry.vue +253 -18
- package/components/form/SelectOrCreateAuthSecret.vue +140 -17
- package/components/form/__tests__/FileSelector.test.ts +23 -0
- package/components/form/__tests__/PrivateRegistry.test.ts +463 -73
- package/components/form/__tests__/SelectOrCreateAuthSecret.test.ts +122 -0
- package/components/formatter/EtcdSnapshotName.vue +73 -0
- package/components/nav/Header.vue +8 -1
- package/components/templates/default.vue +7 -0
- package/config/features.js +1 -0
- package/config/labels-annotations.js +2 -0
- package/config/product/manager.js +6 -0
- package/config/secret.ts +10 -0
- package/config/settings.ts +6 -2
- package/config/types.js +7 -0
- package/detail/provisioning.cattle.io.cluster.vue +79 -3
- package/dialog/RotateEncryptionKeyDialog.vue +33 -9
- package/dialog/__tests__/RotateEncryptionKeyDialog.test.ts +78 -0
- package/edit/__tests__/fleet.cattle.io.gitrepo.test.ts +92 -0
- package/edit/__tests__/fleet.cattle.io.helmop.test.ts +101 -0
- package/edit/__tests__/management.cattle.io.setting.test.ts +2 -1
- package/edit/compliance.cattle.io.clusterscanprofile.vue +39 -41
- package/edit/fleet.cattle.io.gitrepo.vue +70 -16
- package/edit/fleet.cattle.io.helmop.vue +51 -5
- package/edit/helm.cattle.io.projecthelmchart.vue +1 -0
- package/edit/{management.cattle.io.setting.vue → management.cattle.io.setting/index.vue} +32 -9
- package/edit/management.cattle.io.setting/system-default-registry-pull-secrets.vue +81 -0
- package/edit/provisioning.cattle.io.cluster/SelectCredential.vue +3 -12
- package/edit/provisioning.cattle.io.cluster/__tests__/rke2.test.ts +18 -0
- package/edit/provisioning.cattle.io.cluster/rke2.vue +5 -1
- package/edit/provisioning.cattle.io.cluster/tabs/etcd/index.vue +0 -1
- package/edit/provisioning.cattle.io.cluster/tabs/registries/index.vue +14 -55
- package/models/__tests__/provisioning.cattle.io.cluster.test.ts +156 -0
- package/models/__tests__/secret.test.ts +68 -1
- package/models/management.cattle.io.cluster.js +21 -3
- package/models/pod.js +13 -2
- package/models/provisioning.cattle.io.cluster.js +59 -9
- package/models/rke.cattle.io.etcdsnapshot.js +17 -9
- package/models/secret.js +19 -0
- package/models/workload.js +12 -7
- package/package.json +1 -1
- package/pages/c/_cluster/apps/charts/__tests__/install.test.ts +485 -107
- package/pages/c/_cluster/apps/charts/install.vue +114 -28
- package/pkg/require-asset.lib.js +25 -0
- package/pkg/vue.config.js +7 -0
- package/plugins/dashboard-store/__tests__/resource-class.test.ts +84 -0
- package/plugins/dashboard-store/getters.js +0 -1
- package/plugins/dashboard-store/resource-class.js +52 -12
- package/rancher-components/Form/TextArea/TextAreaAutoGrow.vue +30 -0
- package/rancher-components/Form/TextArea/__tests__/TextAreaAutoGrow.test.ts +95 -0
- package/rancher-components/RcButton/index.ts +1 -1
- package/rancher-components/RcDropdown/RcDropdownTrigger.vue +6 -1
- package/store/__tests__/features.test.ts +131 -0
- package/store/__tests__/growl.test.ts +374 -0
- package/store/__tests__/modal.test.ts +131 -0
- package/store/__tests__/slideInPanel.test.ts +88 -0
- package/store/__tests__/type-map.utils.test.ts +433 -0
- package/store/features.js +4 -0
- package/types/shell/index.d.ts +62 -0
- package/utils/__tests__/operation-cr.test.ts +34 -0
- package/utils/operation-cr.js +19 -0
- package/utils/require-asset.ts +7 -0
- package/utils/validators/__tests__/private-registry.test.ts +27 -15
- package/utils/validators/private-registry.ts +15 -4
|
@@ -1,133 +1,523 @@
|
|
|
1
1
|
import { shallowMount } from '@vue/test-utils';
|
|
2
|
+
import { createStore, Store } from 'vuex';
|
|
2
3
|
import PrivateRegistry from '@shell/components/form/PrivateRegistry.vue';
|
|
4
|
+
import { PRIVATE_REGISTRY_CONTEXT } from '@shell/components/form/PrivateRegistry.constants';
|
|
3
5
|
import { Checkbox } from '@components/Form/Checkbox';
|
|
4
6
|
import LabeledInput from '@components/Form/LabeledInput/LabeledInput.vue';
|
|
7
|
+
import SelectOrCreateAuthSecret from '@shell/components/form/SelectOrCreateAuthSecret.vue';
|
|
8
|
+
import Banner from '@components/Banner/Banner.vue';
|
|
9
|
+
import { SETTING } from '@shell/config/settings';
|
|
5
10
|
|
|
6
|
-
const
|
|
7
|
-
|
|
11
|
+
const buildStore = (settings: Record<string, any> = {}): Store<any> => {
|
|
12
|
+
return createStore({
|
|
8
13
|
getters: {
|
|
9
|
-
'i18n/t': (text: string) => text,
|
|
10
|
-
t:
|
|
11
|
-
|
|
12
|
-
|
|
14
|
+
'i18n/t': () => (text: string) => text,
|
|
15
|
+
t: () => (text: string) => text,
|
|
16
|
+
'management/byId': () => (_type: string, id: string) => {
|
|
17
|
+
if (id === SETTING.SYSTEM_DEFAULT_REGISTRY && settings.registry) {
|
|
18
|
+
return { value: settings.registry };
|
|
19
|
+
}
|
|
20
|
+
if (id === SETTING.SYSTEM_DEFAULT_REGISTRY_PULL_SECRETS && settings.pullSecrets) {
|
|
21
|
+
return { value: settings.pullSecrets };
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return null;
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
});
|
|
13
28
|
};
|
|
14
29
|
|
|
15
|
-
const mountPrivateRegistry = (props = {}) => {
|
|
30
|
+
const mountPrivateRegistry = (props = {}, storeSettings: Record<string, any> = {}) => {
|
|
31
|
+
const store = buildStore(storeSettings);
|
|
32
|
+
|
|
16
33
|
return shallowMount(PrivateRegistry, {
|
|
17
34
|
props: {
|
|
18
35
|
mode: 'edit',
|
|
19
36
|
...props
|
|
20
37
|
},
|
|
21
|
-
global: {
|
|
38
|
+
global: {
|
|
39
|
+
plugins: [store],
|
|
40
|
+
mocks: { $store: store }
|
|
41
|
+
}
|
|
22
42
|
});
|
|
23
43
|
};
|
|
24
44
|
|
|
25
45
|
describe('privateRegistry', () => {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
46
|
+
describe('basic rendering', () => {
|
|
47
|
+
it('should render the info banner', () => {
|
|
48
|
+
const wrapper = mountPrivateRegistry();
|
|
49
|
+
const banners = wrapper.findAllComponents(Banner);
|
|
29
50
|
|
|
30
|
-
|
|
31
|
-
|
|
51
|
+
expect(banners.some((b) => b.props('color') === 'info')).toBe(true);
|
|
52
|
+
});
|
|
32
53
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
54
|
+
it('should render the enable checkbox', () => {
|
|
55
|
+
const wrapper = mountPrivateRegistry();
|
|
56
|
+
const checkbox = wrapper.findComponent(Checkbox);
|
|
36
57
|
|
|
37
|
-
|
|
38
|
-
|
|
58
|
+
expect(checkbox.exists()).toBe(true);
|
|
59
|
+
});
|
|
39
60
|
|
|
40
|
-
|
|
41
|
-
|
|
61
|
+
it('should not show the URL input when no value is provided', () => {
|
|
62
|
+
const wrapper = mountPrivateRegistry();
|
|
42
63
|
|
|
43
|
-
|
|
44
|
-
|
|
64
|
+
expect(wrapper.findComponent(LabeledInput).exists()).toBe(false);
|
|
65
|
+
});
|
|
45
66
|
|
|
46
|
-
|
|
47
|
-
|
|
67
|
+
it('should show the URL input when a value is provided', () => {
|
|
68
|
+
const wrapper = mountPrivateRegistry({ value: 'registry.example.com' });
|
|
48
69
|
|
|
49
|
-
|
|
70
|
+
expect(wrapper.findComponent(LabeledInput).exists()).toBe(true);
|
|
71
|
+
});
|
|
50
72
|
});
|
|
51
73
|
|
|
52
|
-
|
|
53
|
-
|
|
74
|
+
describe('enable/disable toggle', () => {
|
|
75
|
+
it('should show the URL input when checkbox is checked', async() => {
|
|
76
|
+
const wrapper = mountPrivateRegistry();
|
|
77
|
+
|
|
78
|
+
expect(wrapper.findComponent(LabeledInput).exists()).toBe(false);
|
|
54
79
|
|
|
55
|
-
|
|
80
|
+
const checkbox = wrapper.findComponent(Checkbox);
|
|
56
81
|
|
|
57
|
-
|
|
82
|
+
await checkbox.vm.$emit('update:value', true);
|
|
83
|
+
await wrapper.vm.$nextTick();
|
|
58
84
|
|
|
59
|
-
|
|
60
|
-
|
|
85
|
+
expect(wrapper.findComponent(LabeledInput).exists()).toBe(true);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
it('should emit update:value with undefined when checkbox is unchecked', async() => {
|
|
89
|
+
const wrapper = mountPrivateRegistry({ value: 'registry.example.com' });
|
|
90
|
+
const checkbox = wrapper.findComponent(Checkbox);
|
|
61
91
|
|
|
62
|
-
|
|
92
|
+
await checkbox.vm.$emit('update:value', false);
|
|
93
|
+
await wrapper.vm.$nextTick();
|
|
94
|
+
|
|
95
|
+
expect(wrapper.emitted('update:value')).toHaveLength(1);
|
|
96
|
+
expect(wrapper.emitted('update:value')![0]).toStrictEqual([undefined]);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it('should emit update:pullSecret with undefined when checkbox is unchecked', async() => {
|
|
100
|
+
const wrapper = mountPrivateRegistry({ value: 'registry.example.com' });
|
|
101
|
+
const checkbox = wrapper.findComponent(Checkbox);
|
|
102
|
+
|
|
103
|
+
await checkbox.vm.$emit('update:value', false);
|
|
104
|
+
await wrapper.vm.$nextTick();
|
|
105
|
+
|
|
106
|
+
expect(wrapper.emitted('update:pullSecret')).toHaveLength(1);
|
|
107
|
+
expect(wrapper.emitted('update:pullSecret')![0]).toStrictEqual([undefined]);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
it('should auto-enable the checkbox when value changes from null to a string', async() => {
|
|
111
|
+
const wrapper = mountPrivateRegistry();
|
|
112
|
+
|
|
113
|
+
expect(wrapper.findComponent(LabeledInput).exists()).toBe(false);
|
|
114
|
+
|
|
115
|
+
await wrapper.setProps({ value: 'registry.example.com' });
|
|
116
|
+
|
|
117
|
+
expect(wrapper.findComponent(LabeledInput).exists()).toBe(true);
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it('should sync showInput when enabled prop changes', async() => {
|
|
121
|
+
const wrapper = mountPrivateRegistry({ enabled: false });
|
|
122
|
+
|
|
123
|
+
expect(wrapper.findComponent(LabeledInput).exists()).toBe(false);
|
|
124
|
+
|
|
125
|
+
await wrapper.setProps({ enabled: true });
|
|
126
|
+
|
|
127
|
+
expect(wrapper.findComponent(LabeledInput).exists()).toBe(true);
|
|
128
|
+
});
|
|
63
129
|
});
|
|
64
130
|
|
|
65
|
-
|
|
66
|
-
|
|
131
|
+
describe('URL input', () => {
|
|
132
|
+
it('should emit update:value when the URL input changes', async() => {
|
|
133
|
+
const wrapper = mountPrivateRegistry({ value: 'registry.example.com' });
|
|
134
|
+
const input = wrapper.findComponent(LabeledInput);
|
|
67
135
|
|
|
68
|
-
|
|
136
|
+
await input.vm.$emit('update:value', 'new-registry.example.com');
|
|
137
|
+
|
|
138
|
+
expect(wrapper.emitted('update:value')).toHaveLength(1);
|
|
139
|
+
expect(wrapper.emitted('update:value')![0]).toStrictEqual(['new-registry.example.com']);
|
|
140
|
+
});
|
|
69
141
|
|
|
70
|
-
|
|
71
|
-
|
|
142
|
+
it('should pass rules to the URL input', () => {
|
|
143
|
+
const mockRule = jest.fn();
|
|
144
|
+
const wrapper = mountPrivateRegistry({
|
|
145
|
+
value: 'registry.example.com',
|
|
146
|
+
rules: [mockRule]
|
|
147
|
+
});
|
|
148
|
+
const input = wrapper.findComponent(LabeledInput);
|
|
72
149
|
|
|
73
|
-
|
|
74
|
-
|
|
150
|
+
expect(input.props('rules')).toBeDefined();
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
it('should use globalRegistry from store as fallback value', async() => {
|
|
154
|
+
const wrapper = mountPrivateRegistry(
|
|
155
|
+
{},
|
|
156
|
+
{ registry: 'global.registry.io' }
|
|
157
|
+
);
|
|
158
|
+
|
|
159
|
+
// Toggle checkbox to show input without setting value
|
|
160
|
+
const checkbox = wrapper.findComponent(Checkbox);
|
|
161
|
+
|
|
162
|
+
await checkbox.vm.$emit('update:value', true);
|
|
163
|
+
await wrapper.vm.$nextTick();
|
|
164
|
+
|
|
165
|
+
const input = wrapper.findComponent(LabeledInput);
|
|
166
|
+
|
|
167
|
+
expect(input.props('value')).toBe('global.registry.io');
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
it('should use defaultRegistry prop over store setting', async() => {
|
|
171
|
+
const wrapper = mountPrivateRegistry(
|
|
172
|
+
{ defaultRegistry: 'prop.registry.io' },
|
|
173
|
+
{ registry: 'store.registry.io' }
|
|
174
|
+
);
|
|
175
|
+
|
|
176
|
+
const checkbox = wrapper.findComponent(Checkbox);
|
|
177
|
+
|
|
178
|
+
await checkbox.vm.$emit('update:value', true);
|
|
179
|
+
await wrapper.vm.$nextTick();
|
|
180
|
+
|
|
181
|
+
const input = wrapper.findComponent(LabeledInput);
|
|
182
|
+
|
|
183
|
+
expect(input.props('value')).toBe('prop.registry.io');
|
|
184
|
+
});
|
|
75
185
|
});
|
|
76
186
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
187
|
+
describe('data-testid', () => {
|
|
188
|
+
it('should apply custom data-testid to checkbox when provided', () => {
|
|
189
|
+
const wrapper = mountPrivateRegistry({ checkboxTestId: 'my-checkbox' });
|
|
190
|
+
const checkbox = wrapper.findComponent(Checkbox);
|
|
191
|
+
|
|
192
|
+
expect(checkbox.attributes('data-testid')).toBe('my-checkbox');
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
it('should apply custom data-testid to input when provided', () => {
|
|
196
|
+
const wrapper = mountPrivateRegistry({
|
|
197
|
+
value: 'registry.example.com',
|
|
198
|
+
inputTestId: 'my-input'
|
|
199
|
+
});
|
|
200
|
+
const input = wrapper.findComponent(LabeledInput);
|
|
80
201
|
|
|
81
|
-
|
|
202
|
+
expect(input.attributes('data-testid')).toBe('my-input');
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
it('should not set data-testid when not provided', () => {
|
|
206
|
+
const wrapper = mountPrivateRegistry({ value: 'registry.example.com' });
|
|
207
|
+
const checkbox = wrapper.findComponent(Checkbox);
|
|
208
|
+
const input = wrapper.findComponent(LabeledInput);
|
|
82
209
|
|
|
83
|
-
|
|
84
|
-
|
|
210
|
+
expect(checkbox.attributes('data-testid')).toBeUndefined();
|
|
211
|
+
expect(input.attributes('data-testid')).toBeUndefined();
|
|
212
|
+
});
|
|
85
213
|
});
|
|
86
214
|
|
|
87
|
-
|
|
88
|
-
|
|
215
|
+
describe('pull secrets section', () => {
|
|
216
|
+
it('should show SelectOrCreateAuthSecret when showPullSecrets is true and value is provided', () => {
|
|
217
|
+
const wrapper = mountPrivateRegistry({
|
|
218
|
+
value: 'registry.example.com',
|
|
219
|
+
showPullSecrets: true
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
expect(wrapper.findComponent(SelectOrCreateAuthSecret).exists()).toBe(true);
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
it('should not show SelectOrCreateAuthSecret when showPullSecrets is false', () => {
|
|
226
|
+
const wrapper = mountPrivateRegistry({
|
|
227
|
+
value: 'registry.example.com',
|
|
228
|
+
showPullSecrets: false
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
expect(wrapper.findComponent(SelectOrCreateAuthSecret).exists()).toBe(false);
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
it('should not show SelectOrCreateAuthSecret when no value is provided', () => {
|
|
235
|
+
const wrapper = mountPrivateRegistry({ showPullSecrets: true });
|
|
236
|
+
|
|
237
|
+
expect(wrapper.findComponent(SelectOrCreateAuthSecret).exists()).toBe(false);
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
it('should pass noneLabel to SelectOrCreateAuthSecret when provided', () => {
|
|
241
|
+
const wrapper = mountPrivateRegistry({
|
|
242
|
+
value: 'registry.example.com',
|
|
243
|
+
noneLabel: 'Custom none label'
|
|
244
|
+
});
|
|
245
|
+
const selector = wrapper.findComponent(SelectOrCreateAuthSecret);
|
|
89
246
|
|
|
90
|
-
|
|
247
|
+
expect(selector.props('noneLabel')).toBe('Custom none label');
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
it('should emit update:pullSecret when SelectOrCreateAuthSecret emits update:value', async() => {
|
|
251
|
+
const wrapper = mountPrivateRegistry({
|
|
252
|
+
value: 'registry.example.com',
|
|
253
|
+
showPullSecrets: true
|
|
254
|
+
});
|
|
255
|
+
const selector = wrapper.findComponent(SelectOrCreateAuthSecret);
|
|
91
256
|
|
|
92
|
-
|
|
257
|
+
await selector.vm.$emit('update:value', 'my-secret');
|
|
93
258
|
|
|
94
|
-
|
|
259
|
+
expect(wrapper.emitted('update:pullSecret')).toHaveLength(1);
|
|
260
|
+
expect(wrapper.emitted('update:pullSecret')![0]).toStrictEqual(['my-secret']);
|
|
261
|
+
});
|
|
95
262
|
});
|
|
96
263
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
264
|
+
describe('default pull secrets', () => {
|
|
265
|
+
it('should load default pull secrets from repoDefaultPullSecrets prop', async() => {
|
|
266
|
+
const wrapper = mountPrivateRegistry({
|
|
267
|
+
value: 'registry.example.com',
|
|
268
|
+
repoDefaultPullSecrets: ['repo-secret-1']
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
await wrapper.vm.$nextTick();
|
|
272
|
+
const selector = wrapper.findComponent(SelectOrCreateAuthSecret);
|
|
273
|
+
|
|
274
|
+
expect(selector.props('noneLabel')).toContain('catalog.chart.registry.pullSecret.defaultLabel');
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
it('should load default pull secrets from store setting when repoDefaultPullSecrets is empty', async() => {
|
|
278
|
+
const wrapper = mountPrivateRegistry(
|
|
279
|
+
{
|
|
280
|
+
value: 'registry.example.com',
|
|
281
|
+
repoDefaultPullSecrets: []
|
|
282
|
+
},
|
|
283
|
+
{ pullSecrets: 'store-secret-1' }
|
|
284
|
+
);
|
|
285
|
+
|
|
286
|
+
await wrapper.vm.$nextTick();
|
|
287
|
+
const selector = wrapper.findComponent(SelectOrCreateAuthSecret);
|
|
288
|
+
|
|
289
|
+
expect(selector.props('noneLabel')).toContain('catalog.chart.registry.pullSecret.defaultLabel');
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
it('should prefer repoDefaultPullSecrets over store setting', async() => {
|
|
293
|
+
const wrapper = mountPrivateRegistry(
|
|
294
|
+
{
|
|
295
|
+
value: 'registry.example.com',
|
|
296
|
+
repoDefaultPullSecrets: ['repo-secret']
|
|
297
|
+
},
|
|
298
|
+
{ pullSecrets: 'store-secret' }
|
|
299
|
+
);
|
|
300
|
+
|
|
301
|
+
await wrapper.vm.$nextTick();
|
|
302
|
+
const selector = wrapper.findComponent(SelectOrCreateAuthSecret);
|
|
303
|
+
|
|
304
|
+
// The label should reference the repo default, not the store one
|
|
305
|
+
expect(selector.props('noneLabel')).toContain('repo-secret');
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
it('should use generic default label when multiple default pull secrets exist', async() => {
|
|
309
|
+
const wrapper = mountPrivateRegistry({
|
|
310
|
+
value: 'registry.example.com',
|
|
311
|
+
repoDefaultPullSecrets: ['secret-1', 'secret-2']
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
await wrapper.vm.$nextTick();
|
|
315
|
+
const selector = wrapper.findComponent(SelectOrCreateAuthSecret);
|
|
316
|
+
|
|
317
|
+
expect(selector.props('noneLabel')).toBe('catalog.chart.registry.pullSecret.defaultLabelGeneric');
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
it('should show defaults banner when multiple default pull secrets exist', async() => {
|
|
321
|
+
const wrapper = mountPrivateRegistry({
|
|
322
|
+
value: 'registry.example.com',
|
|
323
|
+
repoDefaultPullSecrets: ['secret-1', 'secret-2']
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
await wrapper.vm.$nextTick();
|
|
327
|
+
const banners = wrapper.findAllComponents(Banner).filter((b) => b.props('color') === 'info');
|
|
328
|
+
|
|
329
|
+
// Should have at least the description banner + the defaults banner
|
|
330
|
+
expect(banners.length).toBeGreaterThanOrEqual(2);
|
|
102
331
|
});
|
|
103
|
-
const input = wrapper.findComponent(LabeledInput);
|
|
104
332
|
|
|
105
|
-
|
|
333
|
+
it('should not show defaults banner when only one default pull secret exists', () => {
|
|
334
|
+
const wrapper = mountPrivateRegistry({
|
|
335
|
+
value: 'registry.example.com',
|
|
336
|
+
repoDefaultPullSecrets: ['single-secret']
|
|
337
|
+
});
|
|
338
|
+
const banners = wrapper.findAllComponents(Banner).filter((b) => b.props('color') === 'info');
|
|
339
|
+
|
|
340
|
+
// Only the description banner
|
|
341
|
+
expect(banners).toHaveLength(1);
|
|
342
|
+
});
|
|
106
343
|
});
|
|
107
344
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
345
|
+
describe('existing values pull secrets', () => {
|
|
346
|
+
it('should show existing values banner when multiple existing pull secrets are provided', () => {
|
|
347
|
+
const wrapper = mountPrivateRegistry({
|
|
348
|
+
value: 'registry.example.com',
|
|
349
|
+
existingValuesPullSecrets: ['existing-1', 'existing-2']
|
|
350
|
+
});
|
|
351
|
+
const banners = wrapper.findAllComponents(Banner).filter((b) => b.props('color') === 'info');
|
|
352
|
+
|
|
353
|
+
// Description banner + existing values banner
|
|
354
|
+
expect(banners.length).toBeGreaterThanOrEqual(2);
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
it('should hide SelectOrCreateAuthSecret when multiple existing pull secrets are provided', () => {
|
|
358
|
+
const wrapper = mountPrivateRegistry({
|
|
359
|
+
value: 'registry.example.com',
|
|
360
|
+
existingValuesPullSecrets: ['existing-1', 'existing-2']
|
|
361
|
+
});
|
|
362
|
+
|
|
363
|
+
expect(wrapper.findComponent(SelectOrCreateAuthSecret).exists()).toBe(false);
|
|
364
|
+
});
|
|
365
|
+
|
|
366
|
+
it('should show SelectOrCreateAuthSecret when only one existing pull secret is provided', () => {
|
|
367
|
+
const wrapper = mountPrivateRegistry({
|
|
368
|
+
value: 'registry.example.com',
|
|
369
|
+
existingValuesPullSecrets: ['single-existing']
|
|
370
|
+
});
|
|
111
371
|
|
|
112
|
-
|
|
372
|
+
expect(wrapper.findComponent(SelectOrCreateAuthSecret).exists()).toBe(true);
|
|
373
|
+
});
|
|
374
|
+
|
|
375
|
+
it('should show existing values banner instead of defaults banner when both have multiple', () => {
|
|
376
|
+
const wrapper = mountPrivateRegistry({
|
|
377
|
+
value: 'registry.example.com',
|
|
378
|
+
existingValuesPullSecrets: ['existing-1', 'existing-2'],
|
|
379
|
+
repoDefaultPullSecrets: ['default-1', 'default-2']
|
|
380
|
+
});
|
|
381
|
+
// Existing values banner takes priority, defaults banner hidden
|
|
382
|
+
const banners = wrapper.findAllComponents(Banner).filter((b) => b.props('color') === 'info');
|
|
383
|
+
|
|
384
|
+
// Description banner + existing values banner (not defaults banner)
|
|
385
|
+
expect(banners).toHaveLength(2);
|
|
386
|
+
});
|
|
113
387
|
});
|
|
114
388
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
389
|
+
describe('skip pull secrets', () => {
|
|
390
|
+
it('should show skip checkbox only for charts context', () => {
|
|
391
|
+
const wrapper = mountPrivateRegistry({
|
|
392
|
+
value: 'registry.example.com',
|
|
393
|
+
context: PRIVATE_REGISTRY_CONTEXT.CHARTS
|
|
394
|
+
});
|
|
395
|
+
const skipCheckbox = wrapper.find('[data-testid="registry-skip-pull-secrets-checkbox"]');
|
|
396
|
+
|
|
397
|
+
expect(skipCheckbox.exists()).toBe(true);
|
|
119
398
|
});
|
|
120
|
-
const input = wrapper.findComponent(LabeledInput);
|
|
121
399
|
|
|
122
|
-
|
|
400
|
+
it('should not show skip checkbox for provisioning context', () => {
|
|
401
|
+
const wrapper = mountPrivateRegistry({
|
|
402
|
+
value: 'registry.example.com',
|
|
403
|
+
context: PRIVATE_REGISTRY_CONTEXT.PROVISIONING
|
|
404
|
+
});
|
|
405
|
+
const skipCheckbox = wrapper.find('[data-testid="registry-skip-pull-secrets-checkbox"]');
|
|
406
|
+
|
|
407
|
+
expect(skipCheckbox.exists()).toBe(false);
|
|
408
|
+
});
|
|
409
|
+
|
|
410
|
+
it('should hide SelectOrCreateAuthSecret when skip is enabled', async() => {
|
|
411
|
+
const wrapper = mountPrivateRegistry({
|
|
412
|
+
value: 'registry.example.com',
|
|
413
|
+
context: PRIVATE_REGISTRY_CONTEXT.CHARTS
|
|
414
|
+
});
|
|
415
|
+
const skipCheckbox = wrapper.findComponent('[data-testid="registry-skip-pull-secrets-checkbox"]');
|
|
416
|
+
|
|
417
|
+
await skipCheckbox.vm.$emit('update:value', true);
|
|
418
|
+
await wrapper.vm.$nextTick();
|
|
419
|
+
|
|
420
|
+
expect(wrapper.findComponent(SelectOrCreateAuthSecret).exists()).toBe(false);
|
|
421
|
+
});
|
|
422
|
+
|
|
423
|
+
it('should emit update:skipPullSecrets when skip checkbox changes', async() => {
|
|
424
|
+
const wrapper = mountPrivateRegistry({
|
|
425
|
+
value: 'registry.example.com',
|
|
426
|
+
context: PRIVATE_REGISTRY_CONTEXT.CHARTS
|
|
427
|
+
});
|
|
428
|
+
const skipCheckbox = wrapper.findComponent('[data-testid="registry-skip-pull-secrets-checkbox"]');
|
|
429
|
+
|
|
430
|
+
await skipCheckbox.vm.$emit('update:value', true);
|
|
431
|
+
await wrapper.vm.$nextTick();
|
|
432
|
+
|
|
433
|
+
expect(wrapper.emitted('update:skipPullSecrets')).toHaveLength(1);
|
|
434
|
+
expect(wrapper.emitted('update:skipPullSecrets')![0]).toStrictEqual([true]);
|
|
435
|
+
});
|
|
436
|
+
|
|
437
|
+
it('should emit update:pullSecret with undefined when skip is enabled', async() => {
|
|
438
|
+
const wrapper = mountPrivateRegistry({
|
|
439
|
+
value: 'registry.example.com',
|
|
440
|
+
context: PRIVATE_REGISTRY_CONTEXT.CHARTS
|
|
441
|
+
});
|
|
442
|
+
const skipCheckbox = wrapper.findComponent('[data-testid="registry-skip-pull-secrets-checkbox"]');
|
|
443
|
+
|
|
444
|
+
await skipCheckbox.vm.$emit('update:value', true);
|
|
445
|
+
await wrapper.vm.$nextTick();
|
|
446
|
+
|
|
447
|
+
expect(wrapper.emitted('update:pullSecret')).toHaveLength(1);
|
|
448
|
+
expect(wrapper.emitted('update:pullSecret')![0]).toStrictEqual([undefined]);
|
|
449
|
+
});
|
|
450
|
+
|
|
451
|
+
it('should sync localSkipPullSecrets when skipPullSecrets prop changes', async() => {
|
|
452
|
+
const wrapper = mountPrivateRegistry({
|
|
453
|
+
value: 'registry.example.com',
|
|
454
|
+
context: PRIVATE_REGISTRY_CONTEXT.CHARTS,
|
|
455
|
+
skipPullSecrets: false
|
|
456
|
+
});
|
|
457
|
+
|
|
458
|
+
expect(wrapper.findComponent(SelectOrCreateAuthSecret).exists()).toBe(true);
|
|
459
|
+
|
|
460
|
+
await wrapper.setProps({ skipPullSecrets: true });
|
|
461
|
+
|
|
462
|
+
expect(wrapper.findComponent(SelectOrCreateAuthSecret).exists()).toBe(false);
|
|
463
|
+
});
|
|
464
|
+
|
|
465
|
+
it('should hide banners when skip is enabled', async() => {
|
|
466
|
+
const wrapper = mountPrivateRegistry({
|
|
467
|
+
value: 'registry.example.com',
|
|
468
|
+
context: PRIVATE_REGISTRY_CONTEXT.CHARTS,
|
|
469
|
+
repoDefaultPullSecrets: ['secret-1', 'secret-2']
|
|
470
|
+
});
|
|
471
|
+
|
|
472
|
+
await wrapper.vm.$nextTick();
|
|
473
|
+
|
|
474
|
+
const bannersBefore = wrapper.findAllComponents(Banner).filter((b) => b.props('color') === 'info');
|
|
475
|
+
|
|
476
|
+
expect(bannersBefore.length).toBeGreaterThanOrEqual(2);
|
|
477
|
+
|
|
478
|
+
const skipCheckbox = wrapper.findComponent('[data-testid="registry-skip-pull-secrets-checkbox"]');
|
|
479
|
+
|
|
480
|
+
await skipCheckbox.vm.$emit('update:value', true);
|
|
481
|
+
await wrapper.vm.$nextTick();
|
|
482
|
+
|
|
483
|
+
const bannersAfter = wrapper.findAllComponents(Banner).filter((b) => b.props('color') === 'info');
|
|
484
|
+
|
|
485
|
+
// Only the description banner should remain
|
|
486
|
+
expect(bannersAfter).toHaveLength(1);
|
|
487
|
+
});
|
|
123
488
|
});
|
|
124
489
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
490
|
+
describe('pullSecret watcher', () => {
|
|
491
|
+
it('should emit update:value with globalRegistry when pullSecret is set and no value exists', async() => {
|
|
492
|
+
const wrapper = mountPrivateRegistry(
|
|
493
|
+
{ showPullSecrets: true },
|
|
494
|
+
{ registry: 'global.registry.io' }
|
|
495
|
+
);
|
|
129
496
|
|
|
130
|
-
|
|
131
|
-
|
|
497
|
+
await wrapper.setProps({ pullSecret: 'my-secret' });
|
|
498
|
+
|
|
499
|
+
const emitted = wrapper.emitted('update:value');
|
|
500
|
+
|
|
501
|
+
expect(emitted).toBeTruthy();
|
|
502
|
+
expect(emitted![emitted!.length - 1]).toStrictEqual(['global.registry.io']);
|
|
503
|
+
});
|
|
504
|
+
|
|
505
|
+
it('should emit update:value with undefined when pullSecret is cleared and value equals globalRegistry', async() => {
|
|
506
|
+
const wrapper = mountPrivateRegistry(
|
|
507
|
+
{
|
|
508
|
+
value: 'global.registry.io',
|
|
509
|
+
pullSecret: 'my-secret',
|
|
510
|
+
showPullSecrets: true
|
|
511
|
+
},
|
|
512
|
+
{ registry: 'global.registry.io' }
|
|
513
|
+
);
|
|
514
|
+
|
|
515
|
+
await wrapper.setProps({ pullSecret: undefined });
|
|
516
|
+
|
|
517
|
+
const emitted = wrapper.emitted('update:value');
|
|
518
|
+
|
|
519
|
+
expect(emitted).toBeTruthy();
|
|
520
|
+
expect(emitted![emitted!.length - 1]).toStrictEqual([undefined]);
|
|
521
|
+
});
|
|
132
522
|
});
|
|
133
523
|
});
|