@burojs/test-helpers 0.3.0 → 0.5.0

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/README.md CHANGED
@@ -33,14 +33,26 @@ Every locator above is derived from the resource name, so none of these test ids
33
33
 
34
34
  ## Main exports
35
35
 
36
- - **`createBuroPage` / `BuroPage`** — the entry point; wraps a Playwright `Page`. Exposes `resource(name)`, `contextPicker(slice)`, `notification(type)`, `actionConfirm(resource, scope, action)` and the raw `page`.
36
+ - **`createBuroPage` / `BuroPage`** — the entry point; wraps a Playwright `Page`. Exposes `resource(name)`, `contextPicker(slice)`, `notification(type)`, `actionConfirm(resource, scope, action)` (a flow's confirm dialog on a toolbar surface) and the raw `page`.
37
37
  - **`createResourceObject` / `ResourceObject`** — one resource's four surfaces: `list()`, `create()`, `edit(id)`, `show(id)`, plus `picker()`.
38
38
  - **`createFormView` / `FormView` / `FormFieldObject`** — form fields across create/edit/show: `field(name).input()`, `.error()`, `.help()`, and `section(key)`.
39
39
  - **`createShowView` / `ShowView`** — the detail surface (a `FormView` in `show` mode).
40
40
  - **`createPickerObject` / `PickerObject`** — relation pickers, including quick-create.
41
41
  - **`createConfirmDialog` / `ConfirmDialogObject`** — confirmation dialogs raised by declared actions.
42
42
 
43
- The list surface (`documents.list()`) covers `goto()`, `row(id)`, `search()`, `paginationPrev()` / `paginationNext()`, and the filter builder: `filterButton()`, `filterPanel()`, `filterAddRow(groupPath?)`, `filterRowField(path)` / `filterRowOp(path)` / `filterRowValue(path)`, `filterApply()`, `filterReset()`, `filterBadge(index)` / `filterBadgeRemove(index)`, `filterClearAll()` and `filterPinned(field)`.
43
+ The list surface (`documents.list()`) covers `goto()`, `row(id)`, `rows()`, `column(field)`, `columnMenu(field)` / `columnSort(field, direction)`, `search()`, `paginationPrev()` / `paginationNext()`, and the filter builder: `filterButton()`, `filterPanel()`, `filterAddRow(groupPath?)`, `filterRowField(path)` / `filterRowOp(path)` / `filterRowValue(path)`, `filterApply()`, `filterReset()`, `filterBadge(index)` / `filterBadgeRemove(index)`, `filterClearAll()` and `filterPinned(field)`.
44
+
45
+ `rows()` and `column(field)` address a SET — every rendered row, or one column across all of them. They are what a count or an ordering assertion is built on (`await expect(list.rows()).toHaveCount(10)`), and they cannot go through `getByTestId`: those ids embed a record id, so the set is only addressable by prefix.
46
+
47
+ ## Provider contract — a separate entry point
48
+
49
+ `dataProviderContract` (the vitest suite an adapter author runs against a `DataProvider`) lives at `@burojs/test-helpers/provider-contract`, not at the package root:
50
+
51
+ ```ts
52
+ import { dataProviderContract } from '@burojs/test-helpers/provider-contract';
53
+ ```
54
+
55
+ It registers a vitest suite, so it imports `vitest` at module scope. `@vitest/expect` and `@playwright/test` both install `Symbol($$jest-matchers-object)` on `globalThis` and the second to load throws `TypeError: Cannot redefine property` — so a root entry carrying both would make the page objects unimportable from a Playwright spec. Page objects at the root, provider contract at its own path; nothing needs both in one process.
44
56
 
45
57
  ## License
46
58
 
package/dist/index.cjs CHANGED
@@ -1,313 +1,171 @@
1
- 'use strict';
2
-
3
- var core = require('@burojs/core');
4
- var vitest = require('vitest');
5
-
6
- // src/form-view.ts
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ //#region src/form-view.ts
7
3
  function createFormView(page, resource, view) {
8
- return {
9
- field: (fieldName) => {
10
- page.getByTestId(`form-field:${resource}:${view}:${fieldName}`);
11
- return {
12
- input: () => page.getByTestId(`form-field-input:${resource}:${view}:${fieldName}`),
13
- error: () => page.getByTestId(`form-field-error:${resource}:${view}:${fieldName}`),
14
- help: () => page.getByTestId(`form-field-help:${resource}:${view}:${fieldName}`)
15
- };
16
- },
17
- section: (sectionKey) => page.getByTestId(`form-section:${resource}:${view}:${sectionKey}`),
18
- submit: () => page.getByTestId(`form-submit:${resource}:${view}`),
19
- cancel: () => page.getByTestId(`form-cancel:${resource}:${view}`),
20
- action: (actionName) => page.getByTestId(`form-action:${resource}:${view}:${actionName}`)
21
- };
22
- }
23
-
24
- // src/list-view.ts
4
+ return {
5
+ field: (fieldName) => {
6
+ page.getByTestId(`form-field:${resource}:${view}:${fieldName}`);
7
+ return {
8
+ input: () => page.getByTestId(`form-field-input:${resource}:${view}:${fieldName}`),
9
+ error: () => page.getByTestId(`form-field-error:${resource}:${view}:${fieldName}`),
10
+ help: () => page.getByTestId(`form-field-help:${resource}:${view}:${fieldName}`)
11
+ };
12
+ },
13
+ submit: () => page.getByTestId(`form-submit:${resource}:${view}`),
14
+ cancel: () => page.getByTestId(`form-cancel:${resource}:${view}`),
15
+ action: (actionName) => page.getByTestId(`form-action:${resource}:${view}:${actionName}`),
16
+ node: (key, region = "record-body") => page.locator(`[data-buro-region="${region}"] [data-buro-key="${key}"]`)
17
+ };
18
+ }
19
+ //#endregion
20
+ //#region src/list-view.ts
25
21
  function pathStr(path) {
26
- return path.join("-");
22
+ return path.join("-");
27
23
  }
28
24
  function createListView(page, resource, options = {}) {
29
- const path = options.basePath ?? `/${resource}`;
30
- const filterBase = `list-filter:${resource}`;
31
- const rowBase = (rowPath) => `${filterBase}:row:${pathStr(rowPath)}`;
32
- const groupBase = (groupPath) => `${filterBase}:group:${pathStr(groupPath)}`;
33
- return {
34
- goto: async () => {
35
- await page.goto(path);
36
- },
37
- row: (recordId) => createRowObject(page, resource, recordId),
38
- search: () => page.getByTestId(`list-search:${resource}`),
39
- filtersContainer: () => page.getByTestId(`list-filters:${resource}`),
40
- filterButton: () => page.getByTestId(`${filterBase}:button`),
41
- filterPanel: () => page.getByTestId(`${filterBase}:panel`),
42
- filterAddRow: (groupPath = []) => page.getByTestId(`${groupBase(groupPath)}:add-row`),
43
- filterRowField: (rowPath) => page.getByTestId(`${rowBase(rowPath)}:field`),
44
- filterRowFieldOption: (rowPath, field) => page.getByTestId(`${rowBase(rowPath)}:field:option:${field}`),
45
- filterRowOp: (rowPath) => page.getByTestId(`${rowBase(rowPath)}:op`),
46
- filterRowOpOption: (rowPath, op) => page.getByTestId(`${rowBase(rowPath)}:op:option:${op}`),
47
- filterRowValue: (rowPath) => page.getByTestId(`${rowBase(rowPath)}:value`),
48
- filterRowRemove: (rowPath) => page.getByTestId(`${rowBase(rowPath)}:remove`),
49
- filterApply: () => page.getByTestId(`${filterBase}:apply`),
50
- filterReset: () => page.getByTestId(`${filterBase}:reset`),
51
- filterBadge: (index) => page.getByTestId(`${filterBase}:badge:${index}`),
52
- filterBadgeRemove: (index) => page.getByTestId(`${filterBase}:badge:${index}:remove`),
53
- filterClearAll: () => page.getByTestId(`${filterBase}:clear-all`),
54
- filterPinned: (field) => page.getByTestId(`${filterBase}:pinned:${field}`),
55
- paginationPrev: () => page.getByTestId(`list-pagination-prev:${resource}`),
56
- paginationNext: () => page.getByTestId(`list-pagination-next:${resource}`),
57
- empty: () => page.getByTestId(`list-empty:${resource}`),
58
- toolbar: () => page.getByTestId(`list-toolbar:${resource}`),
59
- table: () => page.getByTestId(`list-table:${resource}`)
60
- };
25
+ const path = options.basePath ?? `/${resource}`;
26
+ const filterBase = `list-filter:${resource}`;
27
+ const sortBase = (field) => `list-sort:${resource}:${field}`;
28
+ const rowBase = (rowPath) => `${filterBase}:row:${pathStr(rowPath)}`;
29
+ const groupBase = (groupPath) => `${filterBase}:group:${pathStr(groupPath)}`;
30
+ return {
31
+ goto: async () => {
32
+ await page.goto(path);
33
+ },
34
+ row: (recordId) => createRowObject(page, resource, recordId),
35
+ rows: () => page.locator(`[data-testid^="list-row:${resource}:"]`),
36
+ column: (fieldName) => page.locator(`[data-testid^="list-cell:${resource}:"][data-testid$=":${fieldName}"]`),
37
+ columnMenu: (fieldName) => page.getByTestId(sortBase(fieldName)),
38
+ columnSort: (fieldName, direction) => page.getByTestId(`${sortBase(fieldName)}:sort-${direction}`),
39
+ columnMove: (fieldName, direction) => page.getByTestId(`${sortBase(fieldName)}:move-${direction}`),
40
+ columnsToggle: () => page.getByTestId(`list-columns:${resource}`),
41
+ columnsOption: (columnId) => page.getByTestId(`list-columns-option:${resource}:${columnId}`),
42
+ pageSize: () => page.getByTestId(`list-page-size:${resource}`),
43
+ search: () => page.getByTestId(`list-search:${resource}`),
44
+ filtersContainer: () => page.getByTestId(`list-filters:${resource}`),
45
+ filterButton: () => page.getByTestId(`${filterBase}:button`),
46
+ filterPanel: () => page.getByTestId(`${filterBase}:panel`),
47
+ filterAddRow: (groupPath = []) => page.getByTestId(`${groupBase(groupPath)}:add-row`),
48
+ filterRowField: (rowPath) => page.getByTestId(`${rowBase(rowPath)}:field`),
49
+ filterRowFieldOption: (rowPath, field) => page.getByTestId(`${rowBase(rowPath)}:field:option:${field}`),
50
+ filterRowOp: (rowPath) => page.getByTestId(`${rowBase(rowPath)}:op`),
51
+ filterRowOpOption: (rowPath, op) => page.getByTestId(`${rowBase(rowPath)}:op:option:${op}`),
52
+ filterRowValue: (rowPath) => page.getByTestId(`${rowBase(rowPath)}:value`),
53
+ filterRowRemove: (rowPath) => page.getByTestId(`${rowBase(rowPath)}:remove`),
54
+ filterApply: () => page.getByTestId(`${filterBase}:apply`),
55
+ filterReset: () => page.getByTestId(`${filterBase}:reset`),
56
+ filterBadge: (index) => page.getByTestId(`${filterBase}:badge:${index}`),
57
+ filterBadgeRemove: (index) => page.getByTestId(`${filterBase}:badge:${index}:remove`),
58
+ filterClearAll: () => page.getByTestId(`${filterBase}:clear-all`),
59
+ filterPinned: (field) => page.getByTestId(`${filterBase}:pinned:${field}`),
60
+ bulkBar: () => page.getByTestId(`list-bulk-bar:${resource}`),
61
+ bulkAction: (actionName) => page.getByTestId(`bulk-action:${resource}:${actionName}`),
62
+ paginationPrev: () => page.getByTestId(`list-pagination-prev:${resource}`),
63
+ paginationNext: () => page.getByTestId(`list-pagination-next:${resource}`),
64
+ loadMore: () => page.getByTestId("cursor-load-more"),
65
+ empty: () => page.getByTestId(`list-empty:${resource}`),
66
+ toolbar: () => page.getByTestId(`list-toolbar:${resource}`),
67
+ table: () => page.getByTestId(`list-table:${resource}`),
68
+ savedViews: () => page.getByTestId(`list-saved-views:${resource}`),
69
+ savedViewsMenu: () => page.getByTestId(`list-saved-views-menu:${resource}`),
70
+ savedViewEntries: () => page.locator(`[data-testid^="list-saved-view:${resource}:"]`),
71
+ savedView: (viewId) => page.getByTestId(`list-saved-view:${resource}:${viewId}`),
72
+ savedViewSave: () => page.getByTestId(`list-saved-view-save:${resource}`),
73
+ savedViewSaveInput: () => page.getByTestId(`list-saved-view-save-input:${resource}`),
74
+ savedViewSaveConfirm: () => page.getByTestId(`list-saved-view-save-confirm:${resource}`),
75
+ savedViewManage: () => page.getByTestId(`list-saved-view-manage:${resource}`),
76
+ savedViewManageDelete: (viewId) => page.getByTestId(`list-saved-view-manage-delete:${resource}:${viewId}`)
77
+ };
61
78
  }
62
79
  function createRowObject(page, resource, recordId) {
63
- const rowId = `list-row:${resource}:${recordId}`;
64
- return {
65
- cell: (fieldName) => page.getByTestId(`list-cell:${resource}:${recordId}:${fieldName}`),
66
- action: (actionName) => page.getByTestId(`list-row-action:${resource}:${recordId}:${actionName}`),
67
- checkbox: () => page.getByTestId(`list-row-checkbox:${resource}:${recordId}`),
68
- open: async () => {
69
- await page.getByTestId(rowId).click();
70
- }
71
- };
72
- }
73
-
74
- // src/picker-object.ts
80
+ const rowId = `list-row:${resource}:${recordId}`;
81
+ return {
82
+ root: () => page.getByTestId(rowId),
83
+ cell: (fieldName) => page.getByTestId(`list-cell:${resource}:${recordId}:${fieldName}`),
84
+ action: (actionName) => page.getByTestId(`list-row-action:${resource}:${recordId}:${actionName}`),
85
+ checkbox: () => page.getByTestId(`list-row-checkbox:${resource}:${recordId}`),
86
+ open: async () => {
87
+ await page.getByTestId(rowId).click();
88
+ }
89
+ };
90
+ }
91
+ //#endregion
92
+ //#region src/picker-object.ts
75
93
  function createPickerObject(page, targetResource) {
76
- return {
77
- dialog: () => page.getByTestId(`picker-dialog:${targetResource}`),
78
- popover: () => page.getByTestId(`picker-popover:${targetResource}`),
79
- option: (value) => page.getByTestId(`picker-option:${targetResource}:${value}`),
80
- search: () => page.getByTestId(`picker-search:${targetResource}`),
81
- clear: () => page.getByTestId(`picker-clear:${targetResource}`),
82
- quickCreate: () => page.getByTestId(`picker-quickcreate:${targetResource}`)
83
- };
84
- }
85
-
86
- // src/show-view.ts
87
- function createShowView(page, resource) {
88
- return createFormView(page, resource, "show");
89
- }
90
-
91
- // src/resource-object.ts
94
+ const prefix = `relation-picker:${targetResource}`;
95
+ return {
96
+ trigger: () => page.getByTestId(prefix),
97
+ search: () => page.getByTestId(`${prefix}:search`),
98
+ list: () => page.getByTestId(`${prefix}:list`),
99
+ option: (value) => page.getByTestId(`${prefix}:option:${value}`),
100
+ empty: () => page.getByTestId(`${prefix}:empty`),
101
+ clear: () => page.getByTestId(`${prefix}:clear`),
102
+ advanced: () => page.getByTestId(`${prefix}:advanced`),
103
+ viewAll: () => page.getByTestId(`${prefix}:view-all`),
104
+ dialog: () => page.getByTestId(`relation-picker-dialog:${targetResource}`),
105
+ dialogSearch: () => page.getByTestId(`relation-picker-dialog:${targetResource}:search`),
106
+ unregistered: () => page.getByTestId(`${prefix}:unregistered`)
107
+ };
108
+ }
109
+ //#endregion
110
+ //#region src/show-view.ts
111
+ function createShowView(page, resource, recordId) {
112
+ return {
113
+ ...createFormView(page, resource, "show"),
114
+ root: () => page.getByTestId(`page-show:${resource}:${recordId}`)
115
+ };
116
+ }
117
+ //#endregion
118
+ //#region src/resource-object.ts
92
119
  function createResourceObject(page, name) {
93
- return {
94
- name,
95
- list: (options) => createListView(page, name, options),
96
- edit: (_recordId) => createFormView(page, name, "edit"),
97
- show: (_recordId) => createShowView(page, name),
98
- create: () => createFormView(page, name, "create"),
99
- picker: () => createPickerObject(page, name)
100
- };
101
- }
102
-
103
- // src/buro-page.ts
120
+ return {
121
+ name,
122
+ list: (options) => createListView(page, name, options),
123
+ edit: (_recordId) => createFormView(page, name, "edit"),
124
+ show: (recordId) => createShowView(page, name, recordId),
125
+ create: () => createFormView(page, name, "create"),
126
+ picker: () => createPickerObject(page, name)
127
+ };
128
+ }
129
+ //#endregion
130
+ //#region src/buro-page.ts
104
131
  function createBuroPage(page) {
105
- return {
106
- resource: (name) => createResourceObject(page, name),
107
- contextPicker: (sliceName) => page.getByTestId(`context-picker:${sliceName}`),
108
- notification: (type) => page.getByTestId(`notification:${type}`),
109
- actionConfirm: (resource, scope, actionName) => page.getByTestId(`action-confirm-dialog:${resource}:${scope}:${actionName}`),
110
- page
111
- };
112
- }
113
-
114
- // src/confirm-dialog.ts
132
+ return {
133
+ resource: (name) => createResourceObject(page, name),
134
+ navMenuItem: (resource) => page.getByTestId(`nav-menu-item:${resource}`),
135
+ sidebarCustomPage: (pageKey) => page.getByTestId(`sidebar-custompage:${pageKey}`),
136
+ contextPicker: (sliceName) => page.getByTestId(`context-picker:${sliceName}`),
137
+ contextPickerOption: (sliceName, value) => page.getByTestId(`context-picker-option:${sliceName}:${value}`),
138
+ languageSwitch: () => page.getByTestId("language-switch"),
139
+ languageSwitchOption: (localeCode) => page.getByTestId(`language-switch:${localeCode}`),
140
+ login: () => ({
141
+ email: () => page.getByTestId("login-email"),
142
+ password: () => page.getByTestId("login-password"),
143
+ submit: () => page.getByTestId("login-submit")
144
+ }),
145
+ taskRun: (name) => ({
146
+ root: () => page.getByTestId(`task-run:${name}`),
147
+ progress: () => page.getByTestId(`task-run-progress:${name}`),
148
+ failure: (subject) => page.getByTestId(`task-run-failure:${name}:${subject}`)
149
+ }),
150
+ notification: (type) => page.getByTestId(`notification:${type}`),
151
+ actionConfirm: (resource, scope, actionName) => page.getByTestId(`form-action:${resource}:${scope}:${actionName}:confirm:dialog`),
152
+ page
153
+ };
154
+ }
155
+ //#endregion
156
+ //#region src/confirm-dialog.ts
115
157
  function createConfirmDialog(page, resource, scope, actionName) {
116
- return {
117
- dialog: () => page.getByTestId(`action-confirm-dialog:${resource}:${scope}:${actionName}`),
118
- yes: () => page.getByTestId(`action-confirm-yes:${resource}:${scope}:${actionName}`),
119
- no: () => page.getByTestId(`action-confirm-no:${resource}:${scope}:${actionName}`)
120
- };
121
- }
122
- var SESSION = Object.freeze({
123
- sessionKey: "contract-session",
124
- scopeKey: "contract-scope",
125
- generation: 1
126
- });
127
- var REQUEST_CONTEXT = Object.freeze({ contract: "provider" });
128
- function context(signal) {
129
- return Object.freeze({
130
- signal,
131
- requestContext: REQUEST_CONTEXT,
132
- session: SESSION,
133
- providerServiceKey: "contract-provider"
134
- });
135
- }
136
- function queryShape(kind, value) {
137
- if (kind === "custom") return;
138
- vitest.expect(value).toBeTypeOf("object");
139
- if (kind === "list" || kind === "many")
140
- vitest.expect(value.data).toBeInstanceOf(Array);
141
- if (kind === "one") vitest.expect(value).toHaveProperty("data");
142
- if (kind === "count")
143
- vitest.expect([null, "number"]).toContain(typeof value.total);
144
- }
145
- function observed(fixture, expected, signal) {
146
- vitest.expect(fixture.observeCalls()).toContainEqual(vitest.expect.objectContaining({ ...expected, signal }));
147
- }
148
- async function assertBatch(provider, fixture, operations, expected) {
149
- vitest.expect(provider.batch?.queries).toBeTypeOf("function");
150
- const controller = new AbortController();
151
- const result = await provider.batch.queries(operations, context(controller.signal));
152
- core.validateBatchResult(operations, result);
153
- if (expected !== void 0) vitest.expect(result).toEqual(expected);
154
- for (const entry of result.results) if (entry.status === "error") dataError(entry.error);
155
- observed(
156
- fixture,
157
- { lifecycle: "batch", descriptors: operations.map((operation) => operation.descriptor) },
158
- controller.signal
159
- );
160
- }
161
- function dataError(value) {
162
- vitest.expect(core.isDataError(value)).toBe(true);
163
- }
164
- function livePlan(value) {
165
- vitest.expect(value, "descriptors.live was supplied, so live.open must return a plan").not.toBeNull();
166
- vitest.expect(value).toBeTypeOf("object");
167
- vitest.expect(value?.subscribe).toBeTypeOf("function");
168
- }
169
- function liveDescriptorRequired(hasLiveSlot, descriptor) {
170
- if (!hasLiveSlot) return;
171
- vitest.expect(
172
- descriptor,
173
- "the provider exposes a `live` slot, so the fixture must supply `descriptors.live` \u2014 omitting it silently skips the whole live cell"
174
- ).toBeDefined();
175
- }
176
- function dataProviderContract(name, fixture) {
177
- vitest.describe(`${name} data provider contract`, () => {
178
- for (const kind of ["list", "one", "many", "count", "custom"]) {
179
- vitest.it(`preserves the ${kind} query descriptor and AbortSignal`, async () => {
180
- const provider = await fixture.create();
181
- const descriptor = fixture.descriptors.queries?.[kind];
182
- const handler = provider.queries?.[kind];
183
- if (descriptor === void 0 || handler === void 0) return;
184
- const controller = new AbortController();
185
- const result = await handler(descriptor, context(controller.signal));
186
- queryShape(kind, result);
187
- const expected = fixture.descriptors.expected?.queries?.[kind];
188
- if (expected !== void 0) vitest.expect(result).toEqual(expected);
189
- observed(fixture, { lifecycle: "query", kind, descriptor }, controller.signal);
190
- });
191
- }
192
- for (const kind of [
193
- "createOne",
194
- "createMany",
195
- "updateOne",
196
- "updateMany",
197
- "deleteOne",
198
- "deleteMany",
199
- "custom"
200
- ]) {
201
- vitest.it(`validates ${kind} mutation output and preserves its request`, async () => {
202
- const provider = await fixture.create();
203
- const descriptor = fixture.descriptors.mutations?.[kind];
204
- const handler = provider.mutations?.[kind];
205
- if (descriptor === void 0 || handler === void 0) return;
206
- const controller = new AbortController();
207
- const result = await handler(descriptor, context(controller.signal));
208
- core.validateMutationResult(descriptor, result);
209
- const expected = fixture.descriptors.expected?.mutations?.[kind];
210
- if (expected !== void 0) vitest.expect(result).toEqual(expected);
211
- observed(fixture, { lifecycle: "mutation", kind, descriptor }, controller.signal);
212
- });
213
- }
214
- for (const specimen of fixture.descriptors.errors ?? []) {
215
- vitest.it(`returns a structured error for the ${specimen.lifecycle}.${specimen.kind} error specimen`, async () => {
216
- const provider = await fixture.create();
217
- const controller = new AbortController();
218
- const handler = specimen.lifecycle === "query" ? provider.queries?.[specimen.kind] : provider.mutations?.[specimen.kind];
219
- vitest.expect(handler).toBeTypeOf("function");
220
- try {
221
- await handler(specimen.descriptor, context(controller.signal));
222
- throw new Error("Provider error specimen resolved instead of rejecting.");
223
- } catch (error) {
224
- dataError(error);
225
- }
226
- observed(
227
- fixture,
228
- { lifecycle: specimen.lifecycle, kind: specimen.kind, descriptor: specimen.descriptor },
229
- controller.signal
230
- );
231
- });
232
- }
233
- vitest.it("reports absent optional capabilities without invoking fallback handlers", async () => {
234
- const provider = await fixture.create();
235
- const before = fixture.observeCalls().length;
236
- for (const kind of ["list", "one", "many", "count", "custom"]) {
237
- if (provider.queries?.[kind] === void 0) {
238
- const capability = core.resolveDataCapability(provider, { lifecycle: "query", kind });
239
- vitest.expect(capability).toMatchObject({ kind: "capability", code: "missing-data-capability" });
240
- }
241
- }
242
- for (const kind of [
243
- "createOne",
244
- "createMany",
245
- "updateOne",
246
- "updateMany",
247
- "deleteOne",
248
- "deleteMany",
249
- "custom"
250
- ]) {
251
- if (provider.mutations?.[kind] === void 0) {
252
- const capability = core.resolveDataCapability(provider, { lifecycle: "mutation", kind });
253
- vitest.expect(capability).toMatchObject({ kind: "capability", code: "missing-data-capability" });
254
- }
255
- }
256
- vitest.expect(fixture.observeCalls()).toHaveLength(before);
257
- });
258
- vitest.it("validates batch IDs, kinds, partial errors, and the shared AbortSignal", async () => {
259
- const provider = await fixture.create();
260
- const operations = fixture.descriptors.batch;
261
- if (provider.batch?.queries === void 0 || operations === void 0) return;
262
- await assertBatch(provider, fixture, operations, fixture.descriptors.expected?.batch);
263
- });
264
- for (const [index, operations] of (fixture.descriptors.batchGroups ?? []).entries()) {
265
- vitest.it(`keeps batch group ${index + 1} isolated and validates its partial results`, async () => {
266
- const provider = await fixture.create();
267
- await assertBatch(provider, fixture, operations, void 0);
268
- });
269
- }
270
- for (const kind of ["offset", "cursor"]) {
271
- vitest.it(`preserves ${kind} pagination and its mapped total/page shape`, async () => {
272
- const provider = await fixture.create();
273
- const descriptor = fixture.descriptors.pagination?.[kind];
274
- if (descriptor === void 0 || provider.queries?.list === void 0) return;
275
- const controller = new AbortController();
276
- const result = await provider.queries.list(descriptor, context(controller.signal));
277
- queryShape("list", result);
278
- const expected = fixture.descriptors.expected?.pagination?.[kind];
279
- if (expected !== void 0) vitest.expect(result).toEqual(expected);
280
- observed(fixture, { lifecycle: "query", kind: "list", descriptor }, controller.signal);
281
- });
282
- }
283
- vitest.it("opens live plans with the complete descriptor and subscribes with an AbortSignal", async () => {
284
- const provider = await fixture.create();
285
- const descriptor = fixture.descriptors.live;
286
- liveDescriptorRequired(provider.live !== void 0, descriptor);
287
- if (provider.live === void 0 || descriptor === void 0) return;
288
- const openController = new AbortController();
289
- const plan = await provider.live.open(descriptor, context(openController.signal));
290
- observed(fixture, { lifecycle: "live-open", descriptor }, openController.signal);
291
- livePlan(plan);
292
- if (plan === null) return;
293
- const subscribeController = new AbortController();
294
- const observer = {
295
- next: () => void 0,
296
- status: () => void 0,
297
- error: () => void 0,
298
- complete: () => void 0
299
- };
300
- const unsubscribe = await plan.subscribe(observer, { signal: subscribeController.signal });
301
- observed(fixture, { lifecycle: "live-subscribe" }, subscribeController.signal);
302
- await unsubscribe();
303
- });
304
- });
305
- }
306
-
307
- // src/index.ts
308
- var PACKAGE_NAME = "@burojs/test-helpers";
309
- var PACKAGE_VERSION = "0.0.0";
310
-
158
+ return {
159
+ dialog: () => page.getByTestId(`action-confirm-dialog:${resource}:${scope}:${actionName}`),
160
+ yes: () => page.getByTestId(`action-confirm-yes:${resource}:${scope}:${actionName}`),
161
+ no: () => page.getByTestId(`action-confirm-no:${resource}:${scope}:${actionName}`)
162
+ };
163
+ }
164
+ //#endregion
165
+ //#region src/index.ts
166
+ const PACKAGE_NAME = "@burojs/test-helpers";
167
+ const PACKAGE_VERSION = "0.0.0";
168
+ //#endregion
311
169
  exports.PACKAGE_NAME = PACKAGE_NAME;
312
170
  exports.PACKAGE_VERSION = PACKAGE_VERSION;
313
171
  exports.createBuroPage = createBuroPage;
@@ -317,6 +175,5 @@ exports.createListView = createListView;
317
175
  exports.createPickerObject = createPickerObject;
318
176
  exports.createResourceObject = createResourceObject;
319
177
  exports.createShowView = createShowView;
320
- exports.dataProviderContract = dataProviderContract;
321
- //# sourceMappingURL=index.cjs.map
178
+
322
179
  //# sourceMappingURL=index.cjs.map