@qoretechnologies/reqore 0.78.5-pr.708.gd1c403a → 0.78.5-pr.708.gfe16b52

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/.claude/CLAUDE.md CHANGED
@@ -184,6 +184,12 @@ release on npm.
184
184
  - **Location:** `src/stories/` (e.g. `Collection.stories.tsx`).
185
185
  - **Pattern:** ArgTypes for props, canvas controls, visual testing via Chromatic.
186
186
  - **Command:** `yarn build-storybook` builds the static site.
187
+ - **Touch stories:** a story whose play calls `withTouchScreen` (`src/stories/utils/touchScreen.ts`)
188
+ carries `tags: ['touch']`. `yarn test:stories` runs those stories in their own Vitest project
189
+ (`storybook-touch`), and so their own browser page, after the others; an untagged one fails with
190
+ the reason. Chromium cannot give a page its mouse back after touch emulation: it takes the
191
+ machine's hover and pointer, and a Linux CI runner has no mouse, so every later story in the
192
+ same page would find `(hover: none)`. This never shows on a Mac, which always reports a mouse.
187
193
 
188
194
  ### Verifying a visual fix locally with Qlip — reqore mechanics
189
195
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@qoretechnologies/reqore",
3
- "version": "0.78.5-pr.708.gd1c403a",
3
+ "version": "0.78.5-pr.708.gfe16b52",
4
4
  "description": "ReQore is a highly theme-able and modular UI library for React",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -16,7 +16,7 @@
16
16
  "test": "vitest run --project unit",
17
17
  "test:watch": "vitest --project unit",
18
18
  "test:ci": "vitest run --project unit --reporter=json --outputFile=tests.json",
19
- "test:stories": "vitest run --project storybook",
19
+ "test:stories": "vitest run --project storybook --project storybook-touch",
20
20
  "precheck": "yarn run lint && yarn run test && yarn build:test:prod && yarn build:test",
21
21
  "build": "./node_modules/typescript/bin/tsc --project tsconfig.prod.json",
22
22
  "build:test": "./node_modules/typescript/bin/tsc --noEmit",
package/vitest.config.ts CHANGED
@@ -1,14 +1,67 @@
1
1
  import { qlipVitestPlugin } from '@qoretechnologies/qlip';
2
2
  import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';
3
3
  import { playwright } from '@vitest/browser-playwright';
4
+ import { readFileSync, readdirSync } from 'node:fs';
4
5
  import path from 'node:path';
5
6
  import { fileURLToPath } from 'node:url';
6
- import { defineConfig, mergeConfig } from 'vitest/config';
7
+ import { configDefaults, defineConfig, mergeConfig } from 'vitest/config';
7
8
  import viteConfig from './vite.config';
8
9
 
9
10
  const dirname = path.dirname(fileURLToPath(import.meta.url));
10
11
  const qlipUploadToken = process.env.QLIP_UPLOAD_TOKEN;
11
12
 
13
+ /**
14
+ * Story files with no story tagged `touch`, relative to the project root. The touch project leaves them out,
15
+ * so it does not load every story module only to skip it. Read from the files themselves: tagging a story
16
+ * is all it takes to run it on a touch screen.
17
+ */
18
+ const storyFilesWithoutTouch = (): string[] =>
19
+ readdirSync(path.join(dirname, 'src'), { recursive: true, encoding: 'utf8' })
20
+ .filter((file) => file.endsWith('.stories.tsx'))
21
+ .map((file) => path.join('src', file).split(path.sep).join('/'))
22
+ .filter(
23
+ (file) =>
24
+ !/\btags:\s*\[[^\]]*['"]touch['"]/.test(readFileSync(path.join(dirname, file), 'utf8'))
25
+ );
26
+
27
+ // One plugin for both story projects, so they make one qlip build: one build id, and one upload at the end
28
+ // of the run (the plugin registers its reporter once, however many projects load it).
29
+ const qlip = qlipVitestPlugin({
30
+ auto: true,
31
+ captureOnError: true,
32
+ disableAnimations: true,
33
+ pauseAnimationsAtEnd: true,
34
+ viewport: { width: 1920, height: 1080 },
35
+ // serverUrl omitted — defaults to https://qlip.qoretechnologies.com
36
+ ...(qlipUploadToken ? { upload: { uploadToken: qlipUploadToken } } : {}),
37
+ });
38
+
39
+ // A new object for each project: Vitest names a project's browser instances on the objects themselves.
40
+ const storyBrowser = () => ({
41
+ enabled: true,
42
+ // Vitest 4's @vitest/browser-playwright no longer applies
43
+ // `browser.viewport` to the Playwright context (the line is
44
+ // commented out in the provider), so the context silently falls
45
+ // back to Playwright's 1280×720 default and every capture is
46
+ // clamped to it — while the manifest still records qlip's
47
+ // 1920×1080, yielding blurry, mislabeled snapshots. Pass the
48
+ // viewport through the provider's `contextOptions` (which IS
49
+ // applied) so the browser window matches qlip's capture viewport
50
+ // 1:1 and screenshots come out at their true resolution.
51
+ provider: playwright({
52
+ contextOptions: { viewport: { width: 1920, height: 1080 } },
53
+ }),
54
+ headless: true,
55
+ instances: [{ browser: 'chromium' as const }],
56
+ });
57
+
58
+ const storyTest = {
59
+ setupFiles: ['./.storybook/vitest.setup.ts'],
60
+ // Some interaction stories deliberately render slow content and the shared
61
+ // play-function helpers wait up to ~17s; give them headroom.
62
+ testTimeout: 30000,
63
+ };
64
+
12
65
  export default mergeConfig(
13
66
  viteConfig,
14
67
  defineConfig({
@@ -16,52 +69,50 @@ export default mergeConfig(
16
69
  projects: [
17
70
  // Component/interaction tests: run every story in a real browser via Playwright.
18
71
  // Replaces the former @storybook/test-runner.
72
+ //
73
+ // Stories run in two projects, and so in two browser pages. A story tagged `touch` holds the page as a
74
+ // phone (`withTouchScreen` in src/stories/utils/touchScreen.ts), and Chromium cannot hand that page back
75
+ // as it was: turning its touch emulation off takes the hover and pointer the machine reports, not the
76
+ // ones the browser was launched with. Playwright launches its headless Chromium as a mouse
77
+ // (`--blink-settings=primaryHoverType=2,…,primaryPointerType=4`); a Linux runner reports no mouse, so in
78
+ // CI every story after a touch story in the same page found `(hover: none)` - the hover-only actions
79
+ // shown, the Marquee and NavRail deaf to hover, Table's row menu at the touch size. On a Mac the machine
80
+ // reports a mouse, so the same run passes there.
19
81
  {
20
82
  extends: true,
21
83
  plugins: [
22
- qlipVitestPlugin({
23
- auto: true,
24
- captureOnError: true,
25
- disableAnimations: true,
26
- pauseAnimationsAtEnd: true,
27
- viewport: { width: 1920, height: 1080 },
28
- // serverUrl omitted — defaults to https://qlip.qoretechnologies.com
29
- ...(qlipUploadToken ? { upload: { uploadToken: qlipUploadToken } } : {}),
30
- }),
84
+ qlip,
31
85
  storybookTest({
32
86
  configDir: path.join(dirname, '.storybook'),
33
87
  storybookScript: 'yarn storybook --no-open',
88
+ tags: { exclude: ['touch'] },
34
89
  }),
35
90
  ],
36
91
  test: {
37
92
  name: 'storybook',
38
- // One story file at a time. A touch story turns on Chrome's touch emulation through the DevTools
39
- // protocol (`withTouchScreen`), and that emulation belongs to the whole page: a story file running
40
- // beside it, in another frame, sees a coarse pointer and no hover. In #708's CI, Table's mouse-sized
41
- // row menu measured 44px (the touch size) and the Marquee stories found no hover, while the EntityRow
42
- // and SeverityRow touch stories ran at the same time.
93
+ browser: storyBrowser(),
94
+ ...storyTest,
95
+ },
96
+ },
97
+ // The stories tagged `touch`, in their own page, after the others (one file at a time: the touch
98
+ // screen and the narrowed frame belong to the page).
99
+ {
100
+ extends: true,
101
+ plugins: [
102
+ qlip,
103
+ storybookTest({
104
+ configDir: path.join(dirname, '.storybook'),
105
+ storybookScript: 'yarn storybook --no-open',
106
+ tags: { include: ['touch'] },
107
+ }),
108
+ ],
109
+ test: {
110
+ name: 'storybook-touch',
111
+ exclude: [...configDefaults.exclude, ...storyFilesWithoutTouch()],
43
112
  fileParallelism: false,
44
- browser: {
45
- enabled: true,
46
- // Vitest 4's @vitest/browser-playwright no longer applies
47
- // `browser.viewport` to the Playwright context (the line is
48
- // commented out in the provider), so the context silently falls
49
- // back to Playwright's 1280×720 default and every capture is
50
- // clamped to it — while the manifest still records qlip's
51
- // 1920×1080, yielding blurry, mislabeled snapshots. Pass the
52
- // viewport through the provider's `contextOptions` (which IS
53
- // applied) so the browser window matches qlip's capture viewport
54
- // 1:1 and screenshots come out at their true resolution.
55
- provider: playwright({
56
- contextOptions: { viewport: { width: 1920, height: 1080 } },
57
- }),
58
- headless: true,
59
- instances: [{ browser: 'chromium' }],
60
- },
61
- setupFiles: ['./.storybook/vitest.setup.ts'],
62
- // Some interaction stories deliberately render slow content and the shared
63
- // play-function helpers wait up to ~17s; give them headroom.
64
- testTimeout: 30000,
113
+ sequence: { groupOrder: 1 },
114
+ browser: storyBrowser(),
115
+ ...storyTest,
65
116
  },
66
117
  },
67
118
  // Unit tests: the former Jest suite, now on Vitest + jsdom.