@mechris3/glassbox 0.1.4 → 0.1.6

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 (2) hide show
  1. package/README.md +92 -2
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -102,7 +102,26 @@ await fetch('http://...', { headers: { Authorization: `Bearer ${apiKey}` } });
102
102
 
103
103
  ### Page Objects
104
104
 
105
- Extend `BasePage` — no constructor needed:
105
+ Extend `BasePage` — no constructor needed. The following methods are available via `this`:
106
+
107
+ | Method | Description |
108
+ |--------|-------------|
109
+ | `click(selector)` | Click an element |
110
+ | `fill(selector, value)` | Clear and set an input's value |
111
+ | `type(selector, value, {delay?})` | Type character by character (for autocomplete etc.) |
112
+ | `getText(selector)` | Get an element's text content |
113
+ | `getInputValue(selector)` | Get an input's current value |
114
+ | `getAttribute(selector, attr)` | Get an element's attribute value |
115
+ | `countElements(selector)` | Count matching elements |
116
+ | `isVisible(selector)` | Check if element is visible |
117
+ | `isDisabled(selector)` | Check if element is disabled |
118
+ | `waitForSelector(selector, {timeout?})` | Wait for element to appear (default 5s) |
119
+ | `waitForHidden(selector, {timeout?})` | Wait for element to disappear |
120
+ | `goto(url)` | Navigate (relative URLs resolve against target URL) |
121
+ | `evaluate(script)` | Execute arbitrary JS in the page |
122
+ | `clearSession(origin?)` | Clear cookies and storage |
123
+
124
+ Example:
106
125
 
107
126
  ```typescript
108
127
  // page-objects/login.page.ts
@@ -179,7 +198,78 @@ export default defineConfig({
179
198
  });
180
199
  ```
181
200
 
182
- ### Lifecycle Hooks
201
+ ### Best Practices
202
+
203
+ ### Journeys are pure orchestration
204
+
205
+ A journey's `execute()` method should contain **only** calls to page object methods — no conditionals, no assertions, no direct selectors:
206
+
207
+ ```typescript
208
+ // Good — reads like a user story
209
+ async execute() {
210
+ await this.loginPage.loginAs('alice@company.com', 'alice123');
211
+ await this.dashboardPage.verifyLoaded();
212
+ await this.dashboardPage.navigateToProjects();
213
+ await this.projectsPage.verifyProjectCount(6);
214
+ }
215
+
216
+ // Bad — logic leaking into journey
217
+ async execute() {
218
+ await this.fill('[data-testid="email"]', 'alice@company.com');
219
+ const count = await this.getText('[data-testid="count"]');
220
+ if (parseInt(count) !== 6) throw new Error('wrong');
221
+ }
222
+ ```
223
+
224
+ ### Page objects own everything
225
+
226
+ - **Selectors** — store in a private `selectors` object, never expose them
227
+ - **Interaction** — `loginAs()`, `addTask()`, `filterByStatus()` — intention-revealing names
228
+ - **Validation** — `verifyLoaded()`, `verifyErrorMessage()`, `verifyTaskCount()` — throw descriptive errors on failure
229
+
230
+ ```typescript
231
+ export class ProjectsPage extends BasePage {
232
+ private selectors = {
233
+ projectCard: '[data-testid="project-card"]',
234
+ filterActive: '[data-testid="filter-active"]',
235
+ count: '[data-testid="project-count"]',
236
+ };
237
+
238
+ async filterByActive() {
239
+ await this.click(this.selectors.filterActive);
240
+ }
241
+
242
+ async verifyProjectCount(expected: number) {
243
+ const count = await this.getText(this.selectors.count);
244
+ if (count !== String(expected)) {
245
+ throw new Error(`Expected ${expected} projects, got ${count}`);
246
+ }
247
+ }
248
+ }
249
+ ```
250
+
251
+ ### Selector strategy
252
+
253
+ - Always use `[data-testid="..."]` — never CSS classes, tag names, or DOM structure
254
+ - For repeated items, include an identifier: `[data-testid="task-item-${id}"]`
255
+ - If an element doesn't have a `data-testid`, add one to your app first
256
+
257
+ ### File organisation
258
+
259
+ ```
260
+ glassbox/
261
+ ├── page-objects/
262
+ │ ├── login.page.ts ← one class per file
263
+ │ ├── dashboard.page.ts
264
+ │ └── projects.page.ts
265
+ ├── journeys/
266
+ │ ├── login-and-browse.journey.ts
267
+ │ └── create-task.journey.ts
268
+ └── helpers/
269
+ └── before-each.ts
270
+ ```
271
+
272
+ ## Lifecycle Hooks
183
273
 
184
274
  Run code before/after journeys for test data setup and cleanup:
185
275
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mechris3/glassbox",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
4
4
  "description": "Debugger-style browser automation test runner with live execution control via CDP",
5
5
  "main": "dist/src/index.js",
6
6
  "types": "dist/src/index.d.ts",