@spree/cli 3.0.0 → 3.0.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 (27) hide show
  1. package/dist/index.js +161 -160
  2. package/dist/templates/dashboard-starter/AGENTS.md +71 -0
  3. package/dist/templates/dashboard-starter/README.md +112 -1
  4. package/dist/templates/dashboard-starter/package.json +10 -3
  5. package/dist/templates/dashboard-starter/playwright.config.ts +37 -0
  6. package/dist/templates/dashboard-starter/src/hooks/.gitkeep +0 -0
  7. package/dist/templates/dashboard-starter/src/locales/en.json +3 -0
  8. package/dist/templates/dashboard-starter/src/pages/.gitkeep +0 -0
  9. package/dist/templates/dashboard-starter/src/plugins.ts +16 -6
  10. package/dist/templates/dashboard-starter/src/schemas/.gitkeep +0 -0
  11. package/dist/templates/dashboard-starter/src/slots/.gitkeep +0 -0
  12. package/dist/templates/dashboard-starter/src/tables/.gitkeep +0 -0
  13. package/dist/templates/dashboard-starter/tsconfig.json +1 -0
  14. package/dist/templates/dashboard-starter/vitest.config.ts +14 -0
  15. package/dist/templates/seller-dashboard-starter/AGENTS.md +75 -0
  16. package/dist/templates/seller-dashboard-starter/package.json +10 -3
  17. package/dist/templates/seller-dashboard-starter/playwright.config.ts +37 -0
  18. package/dist/templates/seller-dashboard-starter/src/hooks/.gitkeep +0 -0
  19. package/dist/templates/seller-dashboard-starter/src/locales/en.json +3 -0
  20. package/dist/templates/seller-dashboard-starter/src/pages/.gitkeep +0 -0
  21. package/dist/templates/seller-dashboard-starter/src/plugins.ts +7 -3
  22. package/dist/templates/seller-dashboard-starter/src/schemas/.gitkeep +0 -0
  23. package/dist/templates/seller-dashboard-starter/src/slots/.gitkeep +0 -0
  24. package/dist/templates/seller-dashboard-starter/src/tables/.gitkeep +0 -0
  25. package/dist/templates/seller-dashboard-starter/tsconfig.json +1 -0
  26. package/dist/templates/seller-dashboard-starter/vitest.config.ts +14 -0
  27. package/package.json +2 -2
@@ -0,0 +1,71 @@
1
+ # Agent Instructions
2
+
3
+ This is the Spree admin dashboard for this project — a Vite + React app. The
4
+ shell (routes, chrome, resource pages) ships in `@spree/dashboard`; this
5
+ project holds your customizations.
6
+
7
+ Full docs: https://spreecommerce.org/docs/developer/dashboard/overview
8
+
9
+ ## Imports
10
+
11
+ Import from `@spree/dashboard` — it re-exports the framework and the design
12
+ system, so there is no need to work out which package an export lives in.
13
+
14
+ ```ts
15
+ import { defineDashboardPlugin, useStore, Button, ResourceTable } from '@spree/dashboard'
16
+ ```
17
+
18
+ `@spree/dashboard-core` and `@spree/dashboard-ui` stay importable for the few
19
+ components that exist in both: the design system's takes data as props, the
20
+ framework's fetches its own. The facade gives you the framework's.
21
+
22
+ ## Where code goes
23
+
24
+ Organized by kind, one file per resource — the same layout `@spree/dashboard`
25
+ uses internally.
26
+
27
+ | Directory | Holds | Naming |
28
+ |---|---|---|
29
+ | `src/plugins.ts` | Registrations only: nav, routes, slots, tables | one file |
30
+ | `src/pages/` | One screen each | `brands.tsx` |
31
+ | `src/hooks/` | Admin API wrappers | `use-brands.ts` |
32
+ | `src/tables/` | `defineTable` calls | `brands.tsx` |
33
+ | `src/schemas/` | Zod schema + `FormValues` | `brand.ts` |
34
+ | `src/slots/` | Widgets injected into built-in pages | `product-brand-card.tsx` |
35
+ | `src/locales/` | Your `admin.*` translation keys | `en.json` |
36
+
37
+ Adding a resource touches one file in each directory. Keep `plugins.ts` a map
38
+ of what exists, not an implementation.
39
+
40
+ ## Rules
41
+
42
+ - **The Admin API is the only data source.** Never reach into the Rails app or
43
+ import server-rendered HTML. A missing endpoint is added to the API first.
44
+ - **Wrap API calls in a hook.** Components never call `adminClient` directly.
45
+ - **Query keys are store-scoped.** Build them with `useResourceKey`; a bare
46
+ `['brands']` key leaks one store's data into another after a store switch.
47
+ - **Writes go through `useResourceMutation`**, which maps 422 responses onto
48
+ form fields instead of firing a toast.
49
+ - **Every visible string goes through i18next** — page titles, column labels,
50
+ buttons, empty states, toasts. Never hardcode English in JSX or in a table
51
+ definition. Add each new key to every locale file the project ships.
52
+ - **Schemas hold canonical values, never labels.** Build `{ value, label }`
53
+ pairs at render time so labels stay translatable.
54
+ - **Never embed an SDK entity type in a form-values type.** React Hook Form
55
+ walks every nested key and the SDK's object graph overflows the TypeScript
56
+ compiler.
57
+ - **A sortable or filterable column must be allowlisted for Ransack** on the
58
+ model, or the request fails at runtime.
59
+ - **Destructive actions that fire straight from a click need a confirm** —
60
+ `useConfirm()` with `variant: 'destructive'`.
61
+
62
+ ## Checks
63
+
64
+ ```bash
65
+ pnpm typecheck
66
+ pnpm lint
67
+ pnpm test # unit tests (Vitest, Node environment)
68
+ pnpm build
69
+ ```
70
+
71
+ Test the logic between the UI and the API — query keys, payload mapping, permission predicates. Do not write tests that render a component to assert its markup; that tests React. Use `pnpm test:e2e` when a browser is genuinely needed.
@@ -12,7 +12,7 @@ cp .env.example .env.local # optional — VITE_API_PROXY_TARGET if your API is
12
12
  pnpm dev # http://localhost:5173
13
13
  ```
14
14
 
15
- The dev server proxies `/api` to your Rails backend so the SPA stays same-origin — don't set `VITE_SPREE_API_URL` in dev (it switches the SDK to absolute cross-origin URLs, which breaks on CORS and the auth cookie).
15
+ The dev server proxies `/api` to your server API so the SPA stays same-origin — don't set `VITE_SPREE_API_URL` in dev (it switches the SDK to absolute cross-origin URLs, which breaks on CORS and the auth cookie).
16
16
 
17
17
  Sign in with an admin account — authentication is interactive (JWT + refresh cookie). No API keys belong in `.env.local`: every `VITE_`-prefixed value is compiled into the client bundle.
18
18
 
@@ -29,8 +29,119 @@ That's the whole install. `spreeDashboardPlugin()` (see `vite.config.ts`) discov
29
29
 
30
30
  `src/plugins.ts` is yours — register nav entries, routes, slot widgets, and table columns with `defineDashboardPlugin` from `@spree/dashboard-core`. Same API the distributed plugins use; see the [customization quickstart](https://spreecommerce.org/docs/developer/dashboard/customization/quickstart).
31
31
 
32
+ **Import everything from `@spree/dashboard`.** It re-exports the framework
33
+ (registries, providers, hooks, the Admin API client) and the design system, so
34
+ you never have to remember which package a given export lives in:
35
+
36
+ ```ts
37
+ import { defineDashboardPlugin, useStore, Button, ResourceTable } from '@spree/dashboard'
38
+ ```
39
+
40
+ `@spree/dashboard-core` and `@spree/dashboard-ui` remain installed and
41
+ importable when you want them directly — a handful of components exist in
42
+ both, where the design system's version takes its data as props and the
43
+ framework's fetches its own. The facade gives you the framework's.
44
+
45
+ Brands will not be your only customization, so this starter ships the same layout `@spree/dashboard` uses internally: organized by kind, one file per resource.
46
+
47
+ ```
48
+ src/
49
+ ├── plugins.ts registrations only — the map of what you added
50
+ ├── pages/ one file per screen brands.tsx, brand-detail.tsx
51
+ ├── hooks/ one file per resource use-brands.ts
52
+ ├── tables/ one file per resource brands.tsx
53
+ ├── schemas/ one file per resource brand.ts
54
+ ├── slots/ widgets injected into product-brand-card.tsx
55
+ │ built-in pages
56
+ └── locales/ your translations en.json
57
+ ```
58
+
59
+ Adding a resource touches one file in each directory, which is why the split
60
+ is by kind rather than by feature — you always know where a thing lives.
61
+
62
+ **`pages/`** — a screen composes `ResourceLayout` with a `PageHeader` and
63
+ renders a `ResourceTable` or a form. It does not fetch data itself. Register
64
+ it as a route in `plugins.ts`:
65
+
66
+ ```tsx
67
+ import { BrandsPage } from './pages/brands'
68
+
69
+ defineDashboardPlugin({
70
+ routes: [{ key: 'brands', path: '/brands', component: BrandsPage }],
71
+ })
72
+ ```
73
+
74
+ **`hooks/`** — named `use-<resource>.ts`, each wrapping the Admin API so
75
+ components never call `adminClient` directly. Build query keys with
76
+ `useResourceKey`, which scopes them to the current store; a bare `['brands']`
77
+ key leaks one store's data into another after a store switch. Use
78
+ `useResourceMutation` for writes — it maps 422 responses onto form fields
79
+ instead of firing a toast.
80
+
81
+ ```ts
82
+ import { adminClient, useResourceKey } from '@spree/dashboard-core'
83
+ import { useQuery } from '@tanstack/react-query'
84
+
85
+ export function useBrands() {
86
+ return useQuery({
87
+ queryKey: useResourceKey('brands'),
88
+ queryFn: () => adminClient.request('GET', '/brands'),
89
+ })
90
+ }
91
+ ```
92
+
93
+ **`tables/`** — one `defineTable` call per resource, at module load, imported
94
+ from `plugins.ts` so it registers before the router mounts. Column changes to
95
+ built-in tables (products, orders, customers) live here too. A column marked
96
+ `sortable` or `filterable` must be allowlisted for Ransack on the model, or
97
+ the request fails.
98
+
99
+ **`schemas/`** — the Zod schema, its inferred `FormValues` type and defaults.
100
+ Hold canonical values only, never label strings: build `{ value, label }`
101
+ pairs at render time so labels stay translatable. Never embed an SDK entity
102
+ type (`Product`, `Order`) in a form-values type — React Hook Form walks every
103
+ nested key and the SDK's object graph overflows the TypeScript compiler.
104
+ Inline a short single-file schema instead.
105
+
106
+ **`slots/`** — components you inject into pages the dashboard already
107
+ renders, one file per widget. A slot widget takes its data from the slot's
108
+ context and, on a page with a host form, binds its inputs to that form with
109
+ `useHostForm()` rather than saving anything itself.
110
+
111
+ **`locales/`** — every visible string goes through i18next, including column
112
+ labels and button text. Keys live under a top-level `admin` object. Load the
113
+ bundle once at the top of `plugins.ts`:
114
+
115
+ ```ts
116
+ import { i18n } from '@spree/dashboard-core'
117
+ import en from './locales/en.json'
118
+
119
+ i18n.addResourceBundle('en', 'translation', en, true, true)
120
+ ```
121
+
122
+ ## Test
123
+
124
+ Vitest and Playwright are configured. Playwright needs its browser once:
125
+
126
+ ```bash
127
+ pnpm exec playwright install chromium
128
+ ```
129
+
130
+ ```bash
131
+ pnpm test # unit tests: src/**/*.test.ts
132
+ pnpm test:e2e # end-to-end, through a browser
133
+ ```
134
+
135
+ Unit tests run in Node rather than a DOM, because what is worth testing here is the logic between your UI and the API: query keys, payload mapping, permission predicates. Rendering a component to assert its markup tests React, not your feature — use an end-to-end test when you need a browser.
136
+
137
+ `pnpm test:e2e` starts the dashboard itself and reuses one you already have running, but expects your API to be up (`spree dev`). Point it elsewhere with `E2E_BASE_URL`.
138
+
32
139
  ## Build & deploy
33
140
 
141
+ The app root `Dockerfile` already builds this package and bakes it into the production image, available at `https://yourstore.com/dashboard` URL.
142
+
143
+ If you want to host it elsewhere, eg. on CDN you can build it manually.
144
+
34
145
  ```bash
35
146
  pnpm build # static assets in dist/
36
147
  ```
@@ -8,13 +8,18 @@
8
8
  "dev": "vite",
9
9
  "build": "vite build",
10
10
  "preview": "vite preview",
11
+ "test": "vitest run --passWithNoTests",
12
+ "test:watch": "vitest",
13
+ "test:e2e": "playwright test",
11
14
  "typecheck": "tsc --noEmit",
12
15
  "lint": "biome check .",
13
16
  "lint:fix": "biome check --fix ."
14
17
  },
15
18
  "dependencies": {
16
- "@spree/admin-sdk": "^1.0.0-beta.1",
17
- "@spree/dashboard": "^1.0.0-beta.1",
19
+ "@spree/admin-sdk": "^1.0.0-beta.2",
20
+ "@spree/dashboard": "^1.0.0-beta.3",
21
+ "@spree/dashboard-core": "^1.0.0-beta.3",
22
+ "@spree/dashboard-ui": "^1.0.0-beta.3",
18
23
  "@tanstack/react-query": "^5.100.9",
19
24
  "@tanstack/react-router": "^1.169.2",
20
25
  "react": "^19.2.6",
@@ -22,11 +27,13 @@
22
27
  },
23
28
  "devDependencies": {
24
29
  "@biomejs/biome": "^2.4.14",
30
+ "@playwright/test": "^1.59.1",
25
31
  "@types/react": "^19.2.14",
26
32
  "@types/react-dom": "^19.2.3",
27
33
  "@vitejs/plugin-react": "^6.0.1",
28
34
  "typescript": "~6.0.3",
29
- "vite": "^8.0.16"
35
+ "vite": "^8.0.16",
36
+ "vitest": "^4.1.5"
30
37
  },
31
38
  "packageManager": "pnpm@11.13.1"
32
39
  }
@@ -0,0 +1,37 @@
1
+ import { defineConfig, devices } from '@playwright/test'
2
+
3
+ // End-to-end tests run against your own stack: `spree dev` for the API, and
4
+ // the dev server Playwright starts below. Point them somewhere else with
5
+ // E2E_BASE_URL — a preview build, or a deployed environment.
6
+ const BASE_URL = process.env.E2E_BASE_URL || 'http://localhost:5173'
7
+
8
+ export default defineConfig({
9
+ testDir: './e2e',
10
+ // One worker: specs share a database, so parallel runs interfere unless
11
+ // every spec creates its own records under a unique name.
12
+ fullyParallel: false,
13
+ workers: 1,
14
+ retries: process.env.CI ? 2 : 0,
15
+ timeout: 30_000,
16
+ expect: { timeout: 10_000 },
17
+ reporter: process.env.CI ? [['github'], ['html', { open: 'never' }]] : 'list',
18
+
19
+ use: {
20
+ baseURL: BASE_URL,
21
+ trace: 'on-first-retry',
22
+ screenshot: 'only-on-failure',
23
+ },
24
+
25
+ projects: [{ name: 'chromium', use: { ...devices['Desktop Chrome'] } }],
26
+
27
+ // Starts the dashboard for the run and reuses one you already have open.
28
+ // The API is expected to be running separately (`spree dev`).
29
+ webServer: process.env.E2E_BASE_URL
30
+ ? undefined
31
+ : {
32
+ command: 'pnpm dev --port 5173 --strictPort',
33
+ url: BASE_URL,
34
+ reuseExistingServer: true,
35
+ timeout: 60_000,
36
+ },
37
+ })
@@ -0,0 +1,3 @@
1
+ {
2
+ "admin": {}
3
+ }
@@ -4,20 +4,30 @@
4
4
  // shared registries — the same API distributed plugins use. Imported once
5
5
  // from main.tsx, before the dashboard renders.
6
6
  //
7
+ // Keep this file a map of what you added: the registrations live here, the
8
+ // implementations live in pages/, hooks/, tables/ and schemas/. See the
9
+ // README for what belongs where.
10
+ //
7
11
  // Example:
8
12
  //
9
13
  // import { defineDashboardPlugin } from '@spree/dashboard'
10
14
  // import { AnalyticsPage } from './pages/analytics'
11
15
  //
12
16
  // defineDashboardPlugin({
13
- // nav: [{ key: 'analytics', label: 'Analytics', path: '/analytics', position: 60 }],
17
+ // nav: [{
18
+ // key: 'analytics',
19
+ // label: i18n.t('admin.analytics.nav'),
20
+ // path: '/analytics',
21
+ // position: 650,
22
+ // }],
14
23
  // routes: [{ key: 'analytics', path: '/analytics', component: AnalyticsPage }],
15
24
  // })
16
25
  //
17
- // Building custom pages? Add the framework and design-system packages first —
18
- // `pnpm add @spree/dashboard-core @spree/dashboard-ui` — then import hooks,
19
- // providers, and UI primitives from those.
20
- //
21
26
  // Docs: https://spreecommerce.org/docs/developer/dashboard/customization/quickstart
22
27
 
23
- export {}
28
+ import { i18n } from '@spree/dashboard'
29
+ import en from './locales/en.json'
30
+
31
+ // Merges your `admin.*` keys into the dashboard's namespace without dropping
32
+ // its own. Add a bundle per locale you ship.
33
+ i18n.addResourceBundle('en', 'translation', en, true, true)
@@ -8,6 +8,7 @@
8
8
  "types": ["vite/client"],
9
9
  "skipLibCheck": true,
10
10
  "moduleResolution": "bundler",
11
+ "resolveJsonModule": true,
11
12
  "verbatimModuleSyntax": true,
12
13
  "moduleDetection": "force",
13
14
  "noEmit": true,
@@ -0,0 +1,14 @@
1
+ import { defineConfig } from 'vitest/config'
2
+
3
+ export default defineConfig({
4
+ test: {
5
+ globals: true,
6
+ // Node, not jsdom: what is worth unit-testing here is the logic between
7
+ // your UI and the API — query keys, payload mapping, permission
8
+ // predicates. Rendering a component to assert its markup tests React.
9
+ // Reach for a browser through Playwright instead (`pnpm test:e2e`).
10
+ environment: 'node',
11
+ include: ['src/**/*.{test,spec}.{ts,tsx}'],
12
+ exclude: ['node_modules/**', 'e2e/**', 'dist/**'],
13
+ },
14
+ })
@@ -0,0 +1,75 @@
1
+ # Agent Instructions
2
+
3
+ This is the Spree seller panel for this marketplace — a Vite + React app. The
4
+ shell ships in `@spree/seller-dashboard`; this project holds your
5
+ customizations. Sellers manage their own catalog and orders here.
6
+
7
+ Full docs: https://spreecommerce.org/docs/developer/dashboard/overview
8
+
9
+ The admin dashboard is the reference implementation: when a component is
10
+ useful to both, extract it rather than copying it.
11
+
12
+ ## Imports
13
+
14
+ Import from `@spree/seller-dashboard` — it re-exports the framework and the design
15
+ system, so there is no need to work out which package an export lives in.
16
+
17
+ ```ts
18
+ import { defineDashboardPlugin, useStore, Button, ResourceTable } from '@spree/seller-dashboard'
19
+ ```
20
+
21
+ `@spree/dashboard-core` and `@spree/dashboard-ui` stay importable for the few
22
+ components that exist in both: the design system's takes data as props, the
23
+ framework's fetches its own. The facade gives you the framework's.
24
+
25
+ ## Where code goes
26
+
27
+ Organized by kind, one file per resource — the same layout the panel
28
+ uses internally.
29
+
30
+ | Directory | Holds | Naming |
31
+ |---|---|---|
32
+ | `src/plugins.ts` | Registrations only: nav, slots, tables | one file |
33
+ | `src/pages/` | One screen each | `brands.tsx` |
34
+ | `src/hooks/` | Admin API wrappers | `use-brands.ts` |
35
+ | `src/tables/` | `defineTable` calls | `brands.tsx` |
36
+ | `src/schemas/` | Zod schema + `FormValues` | `brand.ts` |
37
+ | `src/slots/` | Widgets injected into built-in pages | `seller-payout-card.tsx` |
38
+ | `src/locales/` | Your `admin.*` translation keys | `en.json` |
39
+
40
+ Adding a resource touches one file in each directory. Keep `plugins.ts` a map
41
+ of what exists, not an implementation.
42
+
43
+ ## Rules
44
+
45
+ - **The Admin API is the only data source.** Never reach into the Rails app or
46
+ import server-rendered HTML. Seller endpoints are scoped to the signed-in
47
+ seller by the server, never by the client. A missing endpoint is added to the API first.
48
+ - **Wrap API calls in a hook.** Components never call `adminClient` directly.
49
+ - **Query keys are store-scoped.** Build them with `useResourceKey`; a bare
50
+ `['brands']` key leaks one store's data into another after a store switch.
51
+ - **Writes go through `useResourceMutation`**, which maps 422 responses onto
52
+ form fields instead of firing a toast.
53
+ - **Every visible string goes through i18next** — page titles, column labels,
54
+ buttons, empty states, toasts. Never hardcode English in JSX or in a table
55
+ definition. Add each new key to every locale file the project ships.
56
+ - **Schemas hold canonical values, never labels.** Build `{ value, label }`
57
+ pairs at render time so labels stay translatable.
58
+ - **Never embed an SDK entity type in a form-values type.** React Hook Form
59
+ walks every nested key and the SDK's object graph overflows the TypeScript
60
+ compiler.
61
+ - **A sortable or filterable column must be allowlisted for Ransack** on the
62
+ model, or the request fails at runtime.
63
+ - **Destructive actions that fire straight from a click need a confirm** —
64
+ `useConfirm()` with `variant: 'destructive'`.
65
+
66
+ ## Checks
67
+
68
+ ```bash
69
+ pnpm typecheck
70
+ pnpm lint
71
+ pnpm test # unit tests (Vitest, Node environment)
72
+ pnpm build
73
+ ```
74
+
75
+ Test the logic between the UI and the API — query keys, payload mapping, permission predicates. Do not write tests that render a component to assert its markup; that tests React. Use `pnpm test:e2e` when a browser is genuinely needed.
@@ -8,13 +8,18 @@
8
8
  "dev": "vite",
9
9
  "build": "vite build",
10
10
  "preview": "vite preview",
11
+ "test": "vitest run --passWithNoTests",
12
+ "test:watch": "vitest",
13
+ "test:e2e": "playwright test",
11
14
  "typecheck": "tsc --noEmit",
12
15
  "lint": "biome check .",
13
16
  "lint:fix": "biome check --fix ."
14
17
  },
15
18
  "dependencies": {
16
- "@spree/seller-dashboard": "^1.0.0-beta.1",
17
- "@spree/seller-sdk": "^1.0.0-beta.1",
19
+ "@spree/seller-dashboard": "^1.0.0-beta.3",
20
+ "@spree/dashboard-core": "^1.0.0-beta.3",
21
+ "@spree/dashboard-ui": "^1.0.0-beta.3",
22
+ "@spree/seller-sdk": "^1.0.0-beta.2",
18
23
  "@tanstack/react-query": "^5.100.9",
19
24
  "@tanstack/react-router": "^1.169.2",
20
25
  "react": "^19.2.6",
@@ -22,11 +27,13 @@
22
27
  },
23
28
  "devDependencies": {
24
29
  "@biomejs/biome": "^2.4.14",
30
+ "@playwright/test": "^1.59.1",
25
31
  "@types/react": "^19.2.14",
26
32
  "@types/react-dom": "^19.2.3",
27
33
  "@vitejs/plugin-react": "^6.0.1",
28
34
  "typescript": "~6.0.3",
29
- "vite": "^8.0.16"
35
+ "vite": "^8.0.16",
36
+ "vitest": "^4.1.5"
30
37
  },
31
38
  "packageManager": "pnpm@11.13.1"
32
39
  }
@@ -0,0 +1,37 @@
1
+ import { defineConfig, devices } from '@playwright/test'
2
+
3
+ // End-to-end tests run against your own stack: `spree dev` for the API, and
4
+ // the dev server Playwright starts below. Point them somewhere else with
5
+ // E2E_BASE_URL — a preview build, or a deployed environment.
6
+ const BASE_URL = process.env.E2E_BASE_URL || 'http://localhost:5174'
7
+
8
+ export default defineConfig({
9
+ testDir: './e2e',
10
+ // One worker: specs share a database, so parallel runs interfere unless
11
+ // every spec creates its own records under a unique name.
12
+ fullyParallel: false,
13
+ workers: 1,
14
+ retries: process.env.CI ? 2 : 0,
15
+ timeout: 30_000,
16
+ expect: { timeout: 10_000 },
17
+ reporter: process.env.CI ? [['github'], ['html', { open: 'never' }]] : 'list',
18
+
19
+ use: {
20
+ baseURL: BASE_URL,
21
+ trace: 'on-first-retry',
22
+ screenshot: 'only-on-failure',
23
+ },
24
+
25
+ projects: [{ name: 'chromium', use: { ...devices['Desktop Chrome'] } }],
26
+
27
+ // Starts the dashboard for the run and reuses one you already have open.
28
+ // The API is expected to be running separately (`spree dev`).
29
+ webServer: process.env.E2E_BASE_URL
30
+ ? undefined
31
+ : {
32
+ command: 'pnpm dev --port 5174 --strictPort',
33
+ url: BASE_URL,
34
+ reuseExistingServer: true,
35
+ timeout: 60_000,
36
+ },
37
+ })
@@ -6,6 +6,11 @@
6
6
  // here, the same API distributed plugins use. Imported once from main.tsx,
7
7
  // before the panel renders.
8
8
  //
9
+ // Keep this file a map of what you added: the registrations live here, the
10
+ // implementations live in pages/, hooks/, tables/ and schemas/ — one file per
11
+ // resource, the same layout the seller panel uses internally. Translations go
12
+ // in locales/ and merge in with `i18n.addResourceBundle`.
13
+ //
9
14
  // Example — add a payouts page and drop the built-in team screen:
10
15
  //
11
16
  // import { defineDashboardPlugin } from '@spree/seller-dashboard'
@@ -23,8 +28,7 @@
23
28
  //
24
29
  // Slots the built-in screens expose: `seller.team.actions`, `seller.team.after`.
25
30
  //
26
- // Building custom pages? Add the framework and design-system packages first —
27
- // `pnpm add @spree/dashboard-core @spree/dashboard-ui` — then import hooks,
28
- // providers, and UI primitives from those.
31
+ // `@spree/dashboard-core` and `@spree/dashboard-ui` are already installed —
32
+ // import hooks, providers and UI primitives straight from them.
29
33
 
30
34
  export {}
@@ -8,6 +8,7 @@
8
8
  "types": ["vite/client"],
9
9
  "skipLibCheck": true,
10
10
  "moduleResolution": "bundler",
11
+ "resolveJsonModule": true,
11
12
  "allowImportingTsExtensions": true,
12
13
  "verbatimModuleSyntax": true,
13
14
  "moduleDetection": "force",
@@ -0,0 +1,14 @@
1
+ import { defineConfig } from 'vitest/config'
2
+
3
+ export default defineConfig({
4
+ test: {
5
+ globals: true,
6
+ // Node, not jsdom: what is worth unit-testing here is the logic between
7
+ // your UI and the API — query keys, payload mapping, permission
8
+ // predicates. Rendering a component to assert its markup tests React.
9
+ // Reach for a browser through Playwright instead (`pnpm test:e2e`).
10
+ environment: 'node',
11
+ include: ['src/**/*.{test,spec}.{ts,tsx}'],
12
+ exclude: ['node_modules/**', 'e2e/**', 'dist/**'],
13
+ },
14
+ })
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spree/cli",
3
- "version": "3.0.0",
3
+ "version": "3.0.2",
4
4
  "description": "CLI for managing Spree Commerce projects",
5
5
  "type": "module",
6
6
  "bin": {
@@ -45,7 +45,7 @@
45
45
  "typescript": "^6.0.3",
46
46
  "vitest": "^4.1.5",
47
47
  "yaml": "^2.8.4",
48
- "@spree/admin-sdk": "^1.0.0-beta.1"
48
+ "@spree/admin-sdk": "^1.0.0-beta.2"
49
49
  },
50
50
  "engines": {
51
51
  "node": ">=20"