@qoretechnologies/reqraft 0.10.1 → 0.10.2

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.
Files changed (53) hide show
  1. package/dist/index.d.ts +8 -4
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js.map +1 -1
  4. package/dist/utils/lspClient.js +5 -5
  5. package/dist/utils/lspClient.js.map +1 -1
  6. package/package.json +24 -33
  7. package/src/components/dpqlEditor/DpqlEditor.stories.tsx +2 -2
  8. package/src/components/form/engine/FormEngine.stories.tsx +122 -128
  9. package/src/components/form/engine/FormEngineRemote.stories.tsx +2 -2
  10. package/src/components/form/engine/_structuredData/StructuredDataView.stories.tsx +2 -2
  11. package/src/components/form/expressions/ExpressionField.stories.tsx +2 -2
  12. package/src/components/form/expressions/builder/ExpressionBuilder.stories.tsx +2 -2
  13. package/src/components/form/fields/Field.stories.tsx +2 -2
  14. package/src/components/form/fields/array/ArrayAutoField.stories.tsx +2 -2
  15. package/src/components/form/fields/auto/AutoFormField.stories.tsx +2 -2
  16. package/src/components/form/fields/boolean/Boolean.stories.tsx +2 -2
  17. package/src/components/form/fields/byte-size/ByteSize.stories.tsx +2 -2
  18. package/src/components/form/fields/color/Color.stories.tsx +2 -2
  19. package/src/components/form/fields/cron/Cron.stories.tsx +2 -2
  20. package/src/components/form/fields/date/Date.stories.tsx +2 -2
  21. package/src/components/form/fields/file/File.stories.tsx +2 -2
  22. package/src/components/form/fields/long-string/LongString.stories.tsx +2 -2
  23. package/src/components/form/fields/markdown/Markdown.stories.tsx +2 -2
  24. package/src/components/form/fields/number/Number.stories.tsx +2 -2
  25. package/src/components/form/fields/object/Object.stories.tsx +4 -4
  26. package/src/components/form/fields/radio-group/RadioGroup.stories.tsx +2 -2
  27. package/src/components/form/fields/rich-text/RichText.stories.tsx +2 -2
  28. package/src/components/form/fields/schema-definition/SchemaDefinitionField.stories.tsx +2 -2
  29. package/src/components/form/fields/select/Select.stories.tsx +2 -2
  30. package/src/components/form/fields/string/String.stories.tsx +2 -2
  31. package/src/components/form/fields/template/TemplateField.stories.tsx +2 -2
  32. package/src/components/form/fields/url/Url.stories.tsx +2 -2
  33. package/src/components/log/Log.stories.tsx +2 -2
  34. package/src/components/menu/Menu.stories.tsx +2 -2
  35. package/src/components/qonsoleSmartInput/QonsoleSmartInput.stories.tsx +2 -2
  36. package/src/components/smartEditor/SmartEditor.stories.tsx +2 -2
  37. package/src/hooks/useFetch/useFetch.stories.tsx +5 -5
  38. package/src/hooks/useStorage/useStorage.stories.tsx +2 -2
  39. package/src/hooks/useWebSocket/useWebsocket.stories.tsx +2 -2
  40. package/src/index.tsx +8 -6
  41. package/src/stores/currentUser/currentUser.stories.tsx +4 -4
  42. package/src/stories/Tests/utils.ts +1 -1
  43. package/src/types.ts +1 -1
  44. package/vite.config.ts +58 -0
  45. package/vitest.config.ts +69 -0
  46. package/dist/stories/Tests/utils.d.ts +0 -32
  47. package/dist/stories/Tests/utils.d.ts.map +0 -1
  48. package/dist/stories/Tests/utils.js +0 -416
  49. package/dist/stories/Tests/utils.js.map +0 -1
  50. package/dist/types.d.ts +0 -9
  51. package/dist/types.d.ts.map +0 -1
  52. package/dist/types.js +0 -3
  53. package/dist/types.js.map +0 -1
@@ -1,11 +1,9 @@
1
- import {
2
- ReqoreInput
3
- } from '@qoretechnologies/reqore';
1
+ import { ReqoreInput } from '@qoretechnologies/reqore';
4
2
  import { TSizes } from '@qoretechnologies/reqore/dist/constants/sizes';
5
3
  import { IQorusFormSchema } from '@qoretechnologies/ts-toolkit';
6
- import { Meta, StoryObj } from '@storybook/react';
7
- import { expect, fireEvent, fn, userEvent, waitFor, within } from '@storybook/test';
4
+ import { Meta, StoryObj } from '@storybook/react-vite';
8
5
  import { ChangeEvent, useState } from 'react';
6
+ import { expect, fireEvent, fn, userEvent, waitFor, within } from 'storybook/test';
9
7
  import { validateField } from '../../../helpers/validations';
10
8
  import {
11
9
  _testsChangeRichText,
@@ -288,10 +286,9 @@ export const ValueCanBeRemoved: Story = {
288
286
  timeout: 10000,
289
287
  });
290
288
  await _testsClickButton({ selector: '.options-item-remove', nth: 0 });
291
- await waitFor(
292
- () => expect(document.querySelectorAll('.options-item-revert').length).toBe(1),
293
- { timeout: 10000 }
294
- );
289
+ await waitFor(() => expect(document.querySelectorAll('.options-item-revert').length).toBe(1), {
290
+ timeout: 10000,
291
+ });
295
292
  await userEvent.hover(document.querySelectorAll('.system-option')[1]);
296
293
  await waitFor(() => expect(document.querySelector('.options-item-remove')).toBeTruthy(), {
297
294
  timeout: 10000,
@@ -1109,12 +1106,20 @@ export const CompactBasic: Story = {
1109
1106
  '.readfirst-row[data-field="optionWithShortDescription"] .options-readfirst-lock-deps'
1110
1107
  ) as HTMLElement;
1111
1108
  await expect(depLock).toBeTruthy();
1112
- await fireEvent.click(depLock);
1109
+ // userEvent (real pointer sequence) keeps the dropdown popover open —
1110
+ // fireEvent's synthetic click opened it then immediately closed it via the
1111
+ // outside-click handler in the Vitest browser. Wait for the menu ITEM, not
1112
+ // just the "Unlocked by:" divider, before clicking it.
1113
+ await userEvent.click(depLock);
1113
1114
  await _testsWaitForText('Unlocked by:');
1114
- const depEntry = Array.from(
1115
- document.querySelectorAll('.reqore-popover-content .reqore-menu-item')
1116
- ).find((element) => element.textContent?.includes('basicOption')) as HTMLElement;
1117
- await fireEvent.click(depEntry);
1115
+ let depEntry: HTMLElement | undefined;
1116
+ await waitFor(() => {
1117
+ depEntry = Array.from(document.querySelectorAll('.reqore-menu-item')).find((element) =>
1118
+ element.textContent?.includes('basicOption')
1119
+ ) as HTMLElement;
1120
+ expect(depEntry).toBeTruthy();
1121
+ });
1122
+ await userEvent.click(depEntry as HTMLElement);
1118
1123
  await waitFor(
1119
1124
  () =>
1120
1125
  expect(
@@ -1235,9 +1240,7 @@ export const CompactReadOnlyRichText: Story = {
1235
1240
  await _testsClickText('Template option');
1236
1241
  await waitFor(
1237
1242
  () => {
1238
- const card = document.querySelector(
1239
- '.options-readfirst-card[data-field="templateOption"]'
1240
- );
1243
+ const card = document.querySelector('.options-readfirst-card[data-field="templateOption"]');
1241
1244
  expect(card).toBeTruthy();
1242
1245
  const tag = card?.querySelector('.reqore-tag');
1243
1246
  expect(tag).toBeTruthy();
@@ -1247,9 +1250,7 @@ export const CompactReadOnlyRichText: Story = {
1247
1250
  // label must be the resolved name, never the raw reference.
1248
1251
  expect(tag?.textContent).toContain('Test (local)');
1249
1252
  expect(tag?.textContent).not.toContain('$local:test');
1250
- expect(
1251
- card?.querySelector('input, textarea, [contenteditable="true"]')
1252
- ).toBeFalsy();
1253
+ expect(card?.querySelector('input, textarea, [contenteditable="true"]')).toBeFalsy();
1253
1254
  },
1254
1255
  { timeout: 10000 }
1255
1256
  );
@@ -1339,7 +1340,9 @@ export const CompactHashStructuredView: Story = {
1339
1340
  await fireEvent.click(valueChip);
1340
1341
  await waitFor(
1341
1342
  () =>
1342
- expect(document.querySelector('.options-readfirst-card[data-field="orderState"]')).toBeTruthy(),
1343
+ expect(
1344
+ document.querySelector('.options-readfirst-card[data-field="orderState"]')
1345
+ ).toBeTruthy(),
1343
1346
  { timeout: 10000 }
1344
1347
  );
1345
1348
 
@@ -1363,9 +1366,7 @@ export const CompactHashStructuredView: Story = {
1363
1366
  { timeout: 10000 }
1364
1367
  );
1365
1368
  await fireEvent.click(
1366
- document.querySelector(
1367
- '[data-field="orderState"] .options-readfirst-viewmore'
1368
- ) as HTMLElement
1369
+ document.querySelector('[data-field="orderState"] .options-readfirst-viewmore') as HTMLElement
1369
1370
  );
1370
1371
  await _testsWaitForText('Show less'); // fade expanded → full tree on screen
1371
1372
 
@@ -1504,10 +1505,9 @@ export const CompactSensitive: Story = {
1504
1505
  // textarea is exempt: it reflects its VALUE as a text child, which is how
1505
1506
  // the user edits the secret — anything else holding the text is a leak.
1506
1507
  await _testsClickText('••••••');
1507
- await waitFor(
1508
- () => expect(document.querySelector('.options-readfirst-inline')).toBeTruthy(),
1509
- { timeout: 10000 }
1510
- );
1508
+ await waitFor(() => expect(document.querySelector('.options-readfirst-inline')).toBeTruthy(), {
1509
+ timeout: 10000,
1510
+ });
1511
1511
  await _testsWaitForTextToNotExist('super-secret-token', ':not(textarea)');
1512
1512
 
1513
1513
  // Close the editor so the story's hero shot is the MASKED read row — not the
@@ -1578,7 +1578,9 @@ export const CompactOperators: Story = {
1578
1578
  // Single clear: a single-value card hides the editor's own input ✕ (it has
1579
1579
  // no Reqore prop, so the card marks itself `-single` and CSS hides it) and
1580
1580
  // shows the card-action Clear between Fullscreen and Done instead.
1581
- const card = document.querySelector('.options-readfirst-card[data-field="status"]') as HTMLElement;
1581
+ const card = document.querySelector(
1582
+ '.options-readfirst-card[data-field="status"]'
1583
+ ) as HTMLElement;
1582
1584
  await expect(card.className).toContain('options-readfirst-card-single');
1583
1585
  await expect(card.querySelector('.options-readfirst-clear')).toBeInTheDocument();
1584
1586
  const builtInClear = card.querySelector('.reqore-clear-input-button') as HTMLElement | null;
@@ -1657,8 +1659,20 @@ export const CompactSortOrder: Story = {
1657
1659
  compact: true,
1658
1660
  minColumnWidth: '300px',
1659
1661
  options: {
1660
- third: { type: 'string', ui_type: 'string', display_name: 'Third', sort: 3, preselected: true },
1661
- first: { type: 'string', ui_type: 'string', display_name: 'First', sort: 1, preselected: true },
1662
+ third: {
1663
+ type: 'string',
1664
+ ui_type: 'string',
1665
+ display_name: 'Third',
1666
+ sort: 3,
1667
+ preselected: true,
1668
+ },
1669
+ first: {
1670
+ type: 'string',
1671
+ ui_type: 'string',
1672
+ display_name: 'First',
1673
+ sort: 1,
1674
+ preselected: true,
1675
+ },
1662
1676
  second: {
1663
1677
  type: 'string',
1664
1678
  ui_type: 'string',
@@ -1789,9 +1803,7 @@ export const CompactFieldsMenu: Story = {
1789
1803
  await clickFieldsMenuItem('Select all');
1790
1804
  await _testsWaitForText('Notes');
1791
1805
  await fireEvent.click(
1792
- document.querySelector(
1793
- '.readfirst-row[data-field="notes"] .readfirst-action'
1794
- ) as HTMLElement
1806
+ document.querySelector('.readfirst-row[data-field="notes"] .readfirst-action') as HTMLElement
1795
1807
  );
1796
1808
  await _testsWaitForText('Remove field');
1797
1809
  await _testsClickButton({ label: 'Confirm' });
@@ -2025,9 +2037,7 @@ export const CompactOverflowAndStickyHeader: Story = {
2025
2037
  scroller.scrollTop = scroller.scrollHeight;
2026
2038
  await waitFor(() => {
2027
2039
  expect(scroller.scrollTop).toBeGreaterThan(0);
2028
- const search = document.querySelector(
2029
- 'input[placeholder="Filter fields..."]'
2030
- ) as HTMLElement;
2040
+ const search = document.querySelector('input[placeholder="Filter fields..."]') as HTMLElement;
2031
2041
  const scrollerTop = scroller.getBoundingClientRect().top;
2032
2042
  expect(search.getBoundingClientRect().top).toBeGreaterThanOrEqual(scrollerTop - 1);
2033
2043
  expect(search.getBoundingClientRect().top).toBeLessThan(scrollerTop + 150);
@@ -2307,7 +2317,9 @@ export const CompactEnumWithImages: Story = {
2307
2317
 
2308
2318
  // Bug 2: drilling in lists every enum choice WITH its logo (the editor was
2309
2319
  // empty before — it only read `allowed_values`, never the IDE `items`).
2310
- await fireEvent.click(document.querySelector('.readfirst-row[data-field="lang"]') as HTMLElement);
2320
+ await fireEvent.click(
2321
+ document.querySelector('.readfirst-row[data-field="lang"]') as HTMLElement
2322
+ );
2311
2323
  await waitFor(
2312
2324
  () => {
2313
2325
  const card = document.querySelector('.options-readfirst-card[data-field="lang"]');
@@ -2341,9 +2353,21 @@ export const CompactEnumRichtextValue: Story = {
2341
2353
  required: true,
2342
2354
  default_value: { type: 'richtext', value: 'qore' },
2343
2355
  allowed_values: [
2344
- { display_name: 'Qore', value: { type: 'richtext', value: 'qore' }, image: langImg('#c0007a', 'Q') },
2345
- { display_name: 'Python', value: { type: 'richtext', value: 'python' }, image: langImg('#3776ab', 'P') },
2346
- { display_name: 'Java', value: { type: 'richtext', value: 'java' }, image: langImg('#e76f00', 'J') },
2356
+ {
2357
+ display_name: 'Qore',
2358
+ value: { type: 'richtext', value: 'qore' },
2359
+ image: langImg('#c0007a', 'Q'),
2360
+ },
2361
+ {
2362
+ display_name: 'Python',
2363
+ value: { type: 'richtext', value: 'python' },
2364
+ image: langImg('#3776ab', 'P'),
2365
+ },
2366
+ {
2367
+ display_name: 'Java',
2368
+ value: { type: 'richtext', value: 'java' },
2369
+ image: langImg('#e76f00', 'J'),
2370
+ },
2347
2371
  ],
2348
2372
  },
2349
2373
  } as unknown as IOptionsSchema,
@@ -2362,7 +2386,9 @@ export const CompactEnumRichtextValue: Story = {
2362
2386
  { timeout: 10000 }
2363
2387
  );
2364
2388
  // Drill in → the RADIO renders (not a rich-text box) with every language.
2365
- await fireEvent.click(document.querySelector('.readfirst-row[data-field="lang"]') as HTMLElement);
2389
+ await fireEvent.click(
2390
+ document.querySelector('.readfirst-row[data-field="lang"]') as HTMLElement
2391
+ );
2366
2392
  await waitFor(
2367
2393
  () => {
2368
2394
  const card = document.querySelector('.options-readfirst-card[data-field="lang"]');
@@ -2402,9 +2428,13 @@ export const CompactSingleExpand: Story = {
2402
2428
  () => expect(document.querySelector('.readfirst-row[data-field="beta"]')).toBeTruthy(),
2403
2429
  { timeout: 10000 }
2404
2430
  );
2405
- await fireEvent.click(document.querySelector('.readfirst-row[data-field="alpha"]') as HTMLElement);
2431
+ await fireEvent.click(
2432
+ document.querySelector('.readfirst-row[data-field="alpha"]') as HTMLElement
2433
+ );
2406
2434
  await waitFor(() => expect(_isRowOpen('alpha')).toBe(true), { timeout: 10000 });
2407
- await fireEvent.click(document.querySelector('.readfirst-row[data-field="beta"]') as HTMLElement);
2435
+ await fireEvent.click(
2436
+ document.querySelector('.readfirst-row[data-field="beta"]') as HTMLElement
2437
+ );
2408
2438
  await waitFor(
2409
2439
  () => {
2410
2440
  expect(_isRowOpen('beta')).toBe(true);
@@ -2424,9 +2454,13 @@ export const CompactMultiExpand: Story = {
2424
2454
  () => expect(document.querySelector('.readfirst-row[data-field="beta"]')).toBeTruthy(),
2425
2455
  { timeout: 10000 }
2426
2456
  );
2427
- await fireEvent.click(document.querySelector('.readfirst-row[data-field="alpha"]') as HTMLElement);
2457
+ await fireEvent.click(
2458
+ document.querySelector('.readfirst-row[data-field="alpha"]') as HTMLElement
2459
+ );
2428
2460
  await waitFor(() => expect(_isRowOpen('alpha')).toBe(true), { timeout: 10000 });
2429
- await fireEvent.click(document.querySelector('.readfirst-row[data-field="beta"]') as HTMLElement);
2461
+ await fireEvent.click(
2462
+ document.querySelector('.readfirst-row[data-field="beta"]') as HTMLElement
2463
+ );
2430
2464
  await waitFor(
2431
2465
  () => {
2432
2466
  expect(_isRowOpen('beta')).toBe(true);
@@ -2473,8 +2507,18 @@ export const CompactFieldTypes: Story = {
2473
2507
  options: {
2474
2508
  // Text & string
2475
2509
  text: { type: 'string', ui_type: 'string', display_name: 'String', group: 'text' },
2476
- longText: { type: 'string', ui_type: 'long-string', display_name: 'Long string', group: 'text' },
2477
- markdownText: { type: 'string', ui_type: 'markdown', display_name: 'Markdown', group: 'text' },
2510
+ longText: {
2511
+ type: 'string',
2512
+ ui_type: 'long-string',
2513
+ display_name: 'Long string',
2514
+ group: 'text',
2515
+ },
2516
+ markdownText: {
2517
+ type: 'string',
2518
+ ui_type: 'markdown',
2519
+ display_name: 'Markdown',
2520
+ group: 'text',
2521
+ },
2478
2522
  richText: { type: 'richtext', ui_type: 'richtext', display_name: 'Rich text', group: 'text' },
2479
2523
  template: {
2480
2524
  type: 'string',
@@ -2717,7 +2761,10 @@ export const CompactFieldTypes: Story = {
2717
2761
  value: 'A longer paragraph of text that wraps across more than one line in the editor.',
2718
2762
  },
2719
2763
  markdownText: { type: 'string', value: '# Heading\nSome **bold** text' },
2720
- richText: { type: 'richtext', value: [{ type: 'paragraph', children: [{ text: 'rich note' }] }] },
2764
+ richText: {
2765
+ type: 'richtext',
2766
+ value: [{ type: 'paragraph', children: [{ text: 'rich note' }] }],
2767
+ },
2721
2768
  template: { type: 'string', value: '$config:billing_url' },
2722
2769
  schedule: { type: 'string', value: '0 0 * * *' },
2723
2770
  when: { type: 'date', value: '2026-06-09' },
@@ -2901,7 +2948,9 @@ export const CompactFieldTypes: Story = {
2901
2948
  '.readfirst-row[data-field="infoShortDesc"] .options-readfirst-info-slot .options-readfirst-info-toggle'
2902
2949
  ) as HTMLElement
2903
2950
  );
2904
- await _testsWaitForText('A one-line summary shown under the field name and in the hover title.');
2951
+ await _testsWaitForText(
2952
+ 'A one-line summary shown under the field name and in the hover title.'
2953
+ );
2905
2954
  await expect(
2906
2955
  document.querySelector('.readfirst-row[data-field="infoLongDesc"] .options-readfirst-help')
2907
2956
  ).toBeTruthy();
@@ -2981,9 +3030,7 @@ export const CompactFieldTypesEditing: Story = {
2981
3030
 
2982
3031
  // The boolean (value: true) has no built-in clear, so the row-level Clear is
2983
3032
  // the only one — and there is no Revert yet (value matches the original).
2984
- await expect(
2985
- editRow('enabled').querySelectorAll('.reqore-clear-input-button')
2986
- ).toHaveLength(0);
3033
+ await expect(editRow('enabled').querySelectorAll('.reqore-clear-input-button')).toHaveLength(0);
2987
3034
  await expect(editRow('enabled').querySelector('.options-readfirst-clear')).toBeInTheDocument();
2988
3035
  await expect(
2989
3036
  editRow('enabled').querySelector('.options-readfirst-revert')
@@ -2998,69 +3045,6 @@ export const CompactFieldTypesEditing: Story = {
2998
3045
  },
2999
3046
  };
3000
3047
 
3001
- // Same catalog, EVERY field required and NOTHING set, all open: each editor in
3002
- // its required/invalid state — the canary for editors that misbehave on an
3003
- // empty required value.
3004
- export const CompactFieldTypesEditingAllRequired: Story = {
3005
- // chromatic off: every catalog editor mounts live (async) — flaky and snapshot-heavy.
3006
- parameters: { chromatic: { disable: true } },
3007
- args: {
3008
- ...CompactFieldTypes.args,
3009
- expandMode: 'multi' as const,
3010
- options: Object.fromEntries(
3011
- Object.entries(CompactFieldTypes.args!.options as IOptionsSchema).map(([name, option]) => [
3012
- name,
3013
- { ...(option as object), required: true },
3014
- ])
3015
- ) as IOptionsSchema,
3016
- value: {} as IOptions,
3017
- },
3018
- play: async () => {
3019
- await _testsWaitForText('String');
3020
- // Everything is required and unset: the invalid-fields banner shows.
3021
- await _testsWaitForText(/fields are not valid and require attention/);
3022
- await _compactExpandAllRows();
3023
- // The editors render their own required messages (the read-row Required
3024
- // tags are replaced by the editor strip while editing).
3025
- await waitFor(() =>
3026
- expect(
3027
- within(document.body).queryAllByText('This field is required').length
3028
- ).toBeGreaterThan(20)
3029
- );
3030
- // Every catalog row resolves to an editor: built-ins (incl. markdown/cron,
3031
- // bridged into AutoFormField) render natively, and Qorus-domain types
3032
- // (mapper / data-provider) render via componentOverrides. None falls
3033
- // through to the "Unknown type!" tag.
3034
- expect(within(document.body).queryAllByText('Unknown type!')).toHaveLength(0);
3035
-
3036
- // The empty `any` card: custom values are disallowed for `any` (the
3037
- // value's TYPE is picked first), so its only control is the template menu
3038
- // — which therefore renders as a labelled "Set value" trigger instead of
3039
- // the bare ⋮. Picking a type from the menu mounts that type's editor.
3040
- await _testsClickText('Set value');
3041
- await _testsClickText('Set Custom Value');
3042
- // Scope the type pick to the open menu — with every editor expanded, an
3043
- // editor toolbar can carry its own "Text" label.
3044
- await waitFor(() =>
3045
- expect(
3046
- within(document.querySelector('.reqore-menu') as HTMLElement).getByText('Text')
3047
- ).toBeInTheDocument()
3048
- );
3049
- await fireEvent.click(
3050
- within(document.querySelector('.reqore-menu') as HTMLElement).getByText('Text')
3051
- );
3052
- await waitFor(
3053
- () =>
3054
- expect(
3055
- document.querySelector(
3056
- '.options-readfirst-card[data-field="dynamic"] [contenteditable="true"]'
3057
- )
3058
- ).toBeTruthy(),
3059
- { timeout: 10000 }
3060
- );
3061
- },
3062
- };
3063
-
3064
3048
  // required_groups linkage: every member shows a PERSISTENT chip — amber "One of"
3065
3049
  // while unmet (tap-popover → scroll + flash siblings, hover highlights), flipping
3066
3050
  // to a muted-green "Covers" / "Covered by <X>" once satisfied. Members live in
@@ -3115,18 +3099,20 @@ export const CompactRequiredGroups: Story = {
3115
3099
  const groupSelector = document.querySelector(
3116
3100
  '.readfirst-row[data-field="byUrl"] .options-readfirst-required-group'
3117
3101
  ) as HTMLElement;
3118
- await fireEvent.click(groupSelector);
3102
+ // userEvent keeps the dropdown popover open (fireEvent's synthetic click
3103
+ // closes it via the outside-click handler in the Vitest browser).
3104
+ await userEvent.click(groupSelector);
3119
3105
  const memberEntry = await waitFor(
3120
3106
  () => {
3121
- const item = Array.from(
3122
- document.querySelectorAll('.reqore-popover-content .reqore-menu-item')
3123
- ).find((element) => element.textContent?.includes('By host')) as HTMLElement;
3107
+ const item = Array.from(document.querySelectorAll('.reqore-menu-item')).find((element) =>
3108
+ element.textContent?.includes('By host')
3109
+ ) as HTMLElement;
3124
3110
  expect(item).toBeTruthy();
3125
3111
  return item;
3126
3112
  },
3127
3113
  { timeout: 10000 }
3128
3114
  );
3129
- await fireEvent.click(memberEntry);
3115
+ await userEvent.click(memberEntry);
3130
3116
  await waitFor(
3131
3117
  () =>
3132
3118
  expect(
@@ -3230,15 +3216,20 @@ export const CompactOptionDependsOnOptionOrAnotherOption: Story = {
3230
3216
  '.readfirst-row[data-field="RequiredOption6"] .options-readfirst-lock-deps'
3231
3217
  ) as HTMLElement;
3232
3218
  await expect(depLock).toBeTruthy();
3233
- await fireEvent.click(depLock);
3219
+ // userEvent keeps the dropdown popover open (see note above).
3220
+ await userEvent.click(depLock);
3234
3221
  await _testsWaitForText('Unlocked by:');
3235
3222
  await _testsWaitForText('any of:');
3236
3223
 
3237
3224
  // Locate the second blocker from the popover (scroll + flash).
3238
- const depEntry = Array.from(
3239
- document.querySelectorAll('.reqore-popover-content .reqore-menu-item')
3240
- ).find((element) => element.textContent?.includes('Required Option 5')) as HTMLElement;
3241
- await fireEvent.click(depEntry);
3225
+ let depEntry: HTMLElement | undefined;
3226
+ await waitFor(() => {
3227
+ depEntry = Array.from(document.querySelectorAll('.reqore-menu-item')).find((element) =>
3228
+ element.textContent?.includes('Required Option 5')
3229
+ ) as HTMLElement;
3230
+ expect(depEntry).toBeTruthy();
3231
+ });
3232
+ await userEvent.click(depEntry as HTMLElement);
3242
3233
  await waitFor(
3243
3234
  () =>
3244
3235
  expect(
@@ -3336,7 +3327,8 @@ export const CompactOptionDependsOnOptionInRequiredGroup: Story = {
3336
3327
  '.readfirst-row[data-field="RequiredOption6"] .options-readfirst-lock-deps'
3337
3328
  ) as HTMLElement;
3338
3329
  await expect(depLock).toBeTruthy();
3339
- await fireEvent.click(depLock);
3330
+ // userEvent keeps the dropdown popover open (see note above).
3331
+ await userEvent.click(depLock);
3340
3332
  await _testsWaitForText('Unlocked by:');
3341
3333
  // A single flat dependency — no "any of:" grouping.
3342
3334
  await _testsWaitForTextToNotExist('any of:');
@@ -3685,7 +3677,9 @@ export const CompactShowcase: Story = {
3685
3677
  await expect(
3686
3678
  document.querySelector('[data-field="chromeIcon"] .options-readfirst-row-icon')
3687
3679
  ).toBeTruthy();
3688
- await expect(document.querySelector('[data-field="chromeImage"] .reqore-icon img')).toBeTruthy();
3680
+ await expect(
3681
+ document.querySelector('[data-field="chromeImage"] .reqore-icon img')
3682
+ ).toBeTruthy();
3689
3683
  await waitFor(() => {
3690
3684
  // The intent stripe rides the value surface's left border, fed by
3691
3685
  // --readfirst-stripe on the field's BLOCK root. This field carries a
@@ -8,8 +8,8 @@
8
8
  // (the dpqlMockLsp pattern, REST flavour). Each story uses DISTINCT urls:
9
9
  // `query()` caches GETs for 5 minutes, so reusing a url across stories would
10
10
  // serve another story's cached schema.
11
- import { StoryObj } from '@storybook/react';
12
- import { expect, fn, userEvent, waitFor, within } from '@storybook/test';
11
+ import { StoryObj } from '@storybook/react-vite';
12
+ import { expect, fn, userEvent, waitFor, within } from 'storybook/test';
13
13
  import { useState } from 'react';
14
14
  import { StoryMeta } from '../../../types';
15
15
  import { FormEngine } from './FormEngine';
@@ -1,5 +1,5 @@
1
- import { Meta, StoryObj } from '@storybook/react';
2
- import { expect } from '@storybook/test';
1
+ import { Meta, StoryObj } from '@storybook/react-vite';
2
+ import { expect } from 'storybook/test';
3
3
  import { _testsWaitForText } from '../../../../stories/Tests/utils';
4
4
  import { StructuredDataView } from './StructuredDataView';
5
5
 
@@ -1,5 +1,5 @@
1
- import { StoryObj } from '@storybook/react';
2
- import { expect, fn, userEvent, waitFor, within } from '@storybook/test';
1
+ import { StoryObj } from '@storybook/react-vite';
2
+ import { expect, fn, userEvent, waitFor, within } from 'storybook/test';
3
3
  import { useState } from 'react';
4
4
 
5
5
  import { StoryMeta } from '../../../types';
@@ -4,8 +4,8 @@
4
4
  // live server; the IDE's `_testsClickButton` / `_testsSelectItemFromCollection`
5
5
  // helpers are inlined here with `@storybook/test` primitives. The count-based
6
6
  // assertions (`.expression`, `.expression-and`, `.expression-or`) are preserved.
7
- import { StoryObj } from '@storybook/react';
8
- import { expect, fireEvent, fn, userEvent, waitFor, within } from '@storybook/test';
7
+ import { StoryObj } from '@storybook/react-vite';
8
+ import { expect, fireEvent, fn, userEvent, waitFor, within } from 'storybook/test';
9
9
  import { useState } from 'react';
10
10
  import { sleep } from '../../../../../__tests__/utils';
11
11
  import { StoryMeta } from '../../../../types';
@@ -1,5 +1,5 @@
1
- import { StoryObj } from '@storybook/react';
2
- import { expect, fn, within } from '@storybook/test';
1
+ import { StoryObj } from '@storybook/react-vite';
2
+ import { expect, fn, within } from 'storybook/test';
3
3
  import { useState } from 'react';
4
4
 
5
5
  import { StoryMeta } from '../../../types';
@@ -1,6 +1,6 @@
1
1
  import { ReqoreControlGroup } from '@qoretechnologies/reqore';
2
- import { StoryObj } from '@storybook/react';
3
- import { expect, fireEvent, fn, waitFor, within } from '@storybook/test';
2
+ import { StoryObj } from '@storybook/react-vite';
3
+ import { expect, fireEvent, fn, waitFor, within } from 'storybook/test';
4
4
  import { useState } from 'react';
5
5
  import { StoryMeta } from '../../../../types';
6
6
  import { NumberFormField } from '../number/Number';
@@ -8,8 +8,8 @@
8
8
  // The saved-values stories (`StringWithSuggestedValues`,
9
9
  // `StringWithSuggestedAndSavedValues`) and the bare `Connection` story
10
10
  // (InterfaceSelector) are not ported — IDE-only seams.
11
- import { StoryObj } from '@storybook/react';
12
- import { expect, fn, userEvent, waitFor, within } from '@storybook/test';
11
+ import { StoryObj } from '@storybook/react-vite';
12
+ import { expect, fn, userEvent, waitFor, within } from 'storybook/test';
13
13
  import jsyaml from 'js-yaml';
14
14
  import { useState } from 'react';
15
15
 
@@ -1,5 +1,5 @@
1
- import { StoryObj } from '@storybook/react';
2
- import { expect, fn, userEvent, within } from '@storybook/test';
1
+ import { StoryObj } from '@storybook/react-vite';
2
+ import { expect, fn, userEvent, within } from 'storybook/test';
3
3
  import { useState } from 'react';
4
4
 
5
5
  import { StoryMeta } from '../../../../types';
@@ -1,5 +1,5 @@
1
- import { StoryObj } from '@storybook/react';
2
- import { expect, fn, userEvent, waitFor, within } from '@storybook/test';
1
+ import { StoryObj } from '@storybook/react-vite';
2
+ import { expect, fn, userEvent, waitFor, within } from 'storybook/test';
3
3
  import { useState } from 'react';
4
4
  import { StoryMeta } from '../../../../types';
5
5
  import { ByteSizeFormField } from './ByteSize';
@@ -1,5 +1,5 @@
1
- import { StoryObj } from '@storybook/react';
2
- import { expect, fn } from '@storybook/test';
1
+ import { StoryObj } from '@storybook/react-vite';
2
+ import { expect, fn } from 'storybook/test';
3
3
  import { useState } from 'react';
4
4
 
5
5
  import { StoryMeta } from '../../../../types';
@@ -1,5 +1,5 @@
1
- import { StoryObj } from '@storybook/react';
2
- import { expect, fn, userEvent, within } from '@storybook/test';
1
+ import { StoryObj } from '@storybook/react-vite';
2
+ import { expect, fn, userEvent, within } from 'storybook/test';
3
3
  import { useState } from 'react';
4
4
  import { StoryMeta } from '../../../../types';
5
5
  import { CronFormField } from './Cron';
@@ -1,5 +1,5 @@
1
- import { StoryObj } from '@storybook/react';
2
- import { expect, fn } from '@storybook/test';
1
+ import { StoryObj } from '@storybook/react-vite';
2
+ import { expect, fn } from 'storybook/test';
3
3
  import { useState } from 'react';
4
4
 
5
5
  import { StoryMeta } from '../../../../types';
@@ -1,5 +1,5 @@
1
- import { StoryObj } from '@storybook/react';
2
- import { expect, fn, within } from '@storybook/test';
1
+ import { StoryObj } from '@storybook/react-vite';
2
+ import { expect, fn, within } from 'storybook/test';
3
3
  import { useState } from 'react';
4
4
 
5
5
  import { StoryMeta } from '../../../../types';
@@ -1,5 +1,5 @@
1
- import { StoryObj } from '@storybook/react';
2
- import { expect, fn, userEvent, waitFor, within } from '@storybook/test';
1
+ import { StoryObj } from '@storybook/react-vite';
2
+ import { expect, fn, userEvent, waitFor, within } from 'storybook/test';
3
3
  import { useState } from 'react';
4
4
 
5
5
  import { StoryMeta } from '../../../../types';
@@ -1,5 +1,5 @@
1
- import { StoryObj } from '@storybook/react';
2
- import { expect, fn, within } from '@storybook/test';
1
+ import { StoryObj } from '@storybook/react-vite';
2
+ import { expect, fn, within } from 'storybook/test';
3
3
  import { useState } from 'react';
4
4
 
5
5
  import { markdown } from '../../../../../mock/fields';
@@ -1,6 +1,6 @@
1
1
  import { ReqoreControlGroup } from '@qoretechnologies/reqore';
2
- import { StoryObj } from '@storybook/react';
3
- import { expect, fn, userEvent, waitFor, within } from '@storybook/test';
2
+ import { StoryObj } from '@storybook/react-vite';
3
+ import { expect, fn, userEvent, waitFor, within } from 'storybook/test';
4
4
  import { useState } from 'react';
5
5
  import { StoryMeta } from '../../../../types';
6
6
  import { NumberFormField } from './Number';
@@ -1,5 +1,5 @@
1
- import { StoryObj } from '@storybook/react';
2
- import { expect, fireEvent, fn } from '@storybook/test';
1
+ import { StoryObj } from '@storybook/react-vite';
2
+ import { expect, fireEvent, fn } from 'storybook/test';
3
3
  import { useMemo, useState } from 'react';
4
4
 
5
5
  import jsyaml from 'js-yaml';
@@ -155,7 +155,7 @@ export const ValueCanBeRemoved: Story = {
155
155
  },
156
156
  };
157
157
 
158
- export const json: Story = {
158
+ export const Json: Story = {
159
159
  args: {
160
160
  type: 'object',
161
161
  dataType: 'json',
@@ -202,7 +202,7 @@ export const json: Story = {
202
202
  },
203
203
  };
204
204
 
205
- export const yaml: Story = {
205
+ export const Yaml: Story = {
206
206
  args: {
207
207
  type: 'object',
208
208
  dataType: 'yaml',
@@ -1,5 +1,5 @@
1
- import { StoryObj } from '@storybook/react';
2
- import { expect, fn, userEvent, within } from '@storybook/test';
1
+ import { StoryObj } from '@storybook/react-vite';
2
+ import { expect, fn, userEvent, within } from 'storybook/test';
3
3
  import { useState } from 'react';
4
4
 
5
5
  import { StoryMeta } from '../../../../types';
@@ -1,5 +1,5 @@
1
- import { StoryObj } from '@storybook/react';
2
- import { expect, fn, within } from '@storybook/test';
1
+ import { StoryObj } from '@storybook/react-vite';
2
+ import { expect, fn, within } from 'storybook/test';
3
3
  import { useState } from 'react';
4
4
 
5
5
  import { StoryMeta } from '../../../../types';