@cementic/cementic-test 0.2.3
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/LICENSE +201 -0
- package/README.md +625 -0
- package/dist/chunk-J63TUHIV.js +80 -0
- package/dist/chunk-J63TUHIV.js.map +1 -0
- package/dist/cli.js +823 -0
- package/dist/cli.js.map +1 -0
- package/dist/gen-54KYT3RO.js +10 -0
- package/dist/gen-54KYT3RO.js.map +1 -0
- package/dist/templates/student-framework/README.md +13 -0
- package/dist/templates/student-framework/package-lock.json +204 -0
- package/dist/templates/student-framework/package.json +33 -0
- package/dist/templates/student-framework/pages/LandingPage.js +18 -0
- package/dist/templates/student-framework/playwright.config.js +75 -0
- package/dist/templates/student-framework/tests/landing.spec.js +10 -0
- package/dist/templates/student-framework/workflows/playwright.yml +114 -0
- package/package.json +48 -0
package/README.md
ADDED
|
@@ -0,0 +1,625 @@
|
|
|
1
|
+
**README.md** for CementicTest (CT).
|
|
2
|
+
|
|
3
|
+
# CementicTest CLI (v0.2)
|
|
4
|
+
|
|
5
|
+
Turn messy human test ideas into runnable Playwright tests โ while staying 100% compatible with classic Playwright + POM.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
# Run directly (no install needed)
|
|
11
|
+
npx @cementic/cementic-test new my-app
|
|
12
|
+
|
|
13
|
+
# Or install globally
|
|
14
|
+
npm install -g @cementic/cementic-test
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Quick Start
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
# 1. Scaffold a new project
|
|
21
|
+
ct new "Demo"
|
|
22
|
+
|
|
23
|
+
# 2. Generate test cases with AI
|
|
24
|
+
cd Demo
|
|
25
|
+
ct tc --ai --feature "Login" --count 3
|
|
26
|
+
|
|
27
|
+
# 3. Generate & Run
|
|
28
|
+
ct flow
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
# ๐งช CementicTest (CT)
|
|
34
|
+
|
|
35
|
+
### **AI-Assisted Playwright Automation โ From Test Cases to POM Test Suites in Minutes**
|
|
36
|
+
|
|
37
|
+
CementicTest (CT) is a CLI tool that turns **written or AI-generated test cases** into a complete, production-ready **Playwright + Page Object Model** automation framework.
|
|
38
|
+
|
|
39
|
+
CT can:
|
|
40
|
+
|
|
41
|
+
* Scaffold new Playwright projects
|
|
42
|
+
* Scrape real URLs for UI context
|
|
43
|
+
* Generate test cases using LLMs (Bring Your Own API Key)
|
|
44
|
+
* Normalize test cases
|
|
45
|
+
* Generate full Playwright tests using POM standards
|
|
46
|
+
* Run everything instantly via `ct test`
|
|
47
|
+
* Enhance existing Playwright projects
|
|
48
|
+
* Allow optional migration from raw PW โ CT-powered PW
|
|
49
|
+
|
|
50
|
+
CT removes boilerplate, enforces good practices, and massively accelerates setup and test authoring.
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
# โญ๏ธ Features Overview
|
|
55
|
+
|
|
56
|
+
## โ
**1. Project Initialization (POM-ready workspace)**
|
|
57
|
+
|
|
58
|
+
`ct new "<projectName>"` creates a complete, ready-to-run test project:
|
|
59
|
+
|
|
60
|
+
```
|
|
61
|
+
pages/
|
|
62
|
+
tests/
|
|
63
|
+
utils/
|
|
64
|
+
test-data/
|
|
65
|
+
cases/
|
|
66
|
+
.cementic/
|
|
67
|
+
normalized/
|
|
68
|
+
playwright.config.ts
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Includes:
|
|
72
|
+
|
|
73
|
+
* Installed Playwright & browsers
|
|
74
|
+
* Sample login page
|
|
75
|
+
* Sample test
|
|
76
|
+
* Opinionated project structure
|
|
77
|
+
* POM-first architecture layout
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
## โ
**2. AI-powered Test Case Writer**
|
|
82
|
+
|
|
83
|
+
Using your own LLM API key (`CT_LLM_API_KEY`, `OPENAI_API_KEY`, etc.):
|
|
84
|
+
|
|
85
|
+
* Scrapes page content
|
|
86
|
+
* Extracts headings, buttons, inputs, metadata
|
|
87
|
+
* Sends prompt + test spec to LLM
|
|
88
|
+
* Generates structured Markdown test cases:
|
|
89
|
+
|
|
90
|
+
```
|
|
91
|
+
# AUTH-001 โ Valid Login @smoke @auth
|
|
92
|
+
## Steps
|
|
93
|
+
1. Navigate to /login
|
|
94
|
+
...
|
|
95
|
+
## Expected
|
|
96
|
+
- Dashboard loads
|
|
97
|
+
- User profile visible
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Supports:
|
|
101
|
+
|
|
102
|
+
### **Interactive writing**
|
|
103
|
+
|
|
104
|
+
```
|
|
105
|
+
ct tc
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### **AI-writing**
|
|
109
|
+
|
|
110
|
+
```
|
|
111
|
+
ct tc --ai
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### **URL-aware AI-writing (scrape + understand UI)**
|
|
115
|
+
|
|
116
|
+
```
|
|
117
|
+
ct tc url https://mini-bank.testamplify.com/login --ai
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## โ
**3. Test Case Normalization**
|
|
123
|
+
|
|
124
|
+
CT normalizes Markdown test cases into structured machine-readable JSON.
|
|
125
|
+
|
|
126
|
+
```
|
|
127
|
+
ct normalize ./cases
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Output goes to:
|
|
131
|
+
|
|
132
|
+
```
|
|
133
|
+
.cementic/normalized/*.json
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Each JSON contains:
|
|
137
|
+
|
|
138
|
+
* ID
|
|
139
|
+
* Title
|
|
140
|
+
* Steps (array)
|
|
141
|
+
* Expected results
|
|
142
|
+
* Metadata / tags
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
## โ
**4. Automatic Playwright Test Generation**
|
|
147
|
+
|
|
148
|
+
Once normalized, CT can generate full Playwright tests using the POM architecture:
|
|
149
|
+
|
|
150
|
+
```
|
|
151
|
+
ct gen --lang ts
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Generated tests go into:
|
|
155
|
+
|
|
156
|
+
```
|
|
157
|
+
tests/*.spec.ts
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
Generated tests **import your Page Objects**:
|
|
161
|
+
|
|
162
|
+
```ts
|
|
163
|
+
import { LoginPage } from "../pages/login.page";
|
|
164
|
+
|
|
165
|
+
test('AUTH-001 โ Valid Login', async ({ page }) => {
|
|
166
|
+
const login = new LoginPage(page);
|
|
167
|
+
await login.goto();
|
|
168
|
+
await login.login("user", "pass");
|
|
169
|
+
});
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
## โ
**5. Normalize + Generate in one shot**
|
|
175
|
+
|
|
176
|
+
Most developers will use:
|
|
177
|
+
|
|
178
|
+
```
|
|
179
|
+
ct normalize ./cases --and-gen --lang ts
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
This:
|
|
183
|
+
|
|
184
|
+
1. Normalizes test cases โ JSON
|
|
185
|
+
2. Generates Playwright tests immediately
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
189
|
+
## โ
**6. Execute Playwright tests**
|
|
190
|
+
|
|
191
|
+
CT wraps Playwright for convenience:
|
|
192
|
+
|
|
193
|
+
```
|
|
194
|
+
ct test
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
Equivalent to:
|
|
198
|
+
|
|
199
|
+
```
|
|
200
|
+
npx playwright test
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
---
|
|
204
|
+
|
|
205
|
+
## โ
**7. Bring Your Own LLM (BYO LLM API key)**
|
|
206
|
+
|
|
207
|
+
CT is **LLM-agnostic**, meaning it does NOT force you to use OpenAI.
|
|
208
|
+
|
|
209
|
+
You can set:
|
|
210
|
+
|
|
211
|
+
```
|
|
212
|
+
CT_LLM_API_KEY
|
|
213
|
+
OPENAI_API_KEY
|
|
214
|
+
CT_LLM_MODEL
|
|
215
|
+
CT_LLM_BASE_URL
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
Works with:
|
|
219
|
+
|
|
220
|
+
* OpenAI
|
|
221
|
+
* Anthropic (Claude-compatible proxies)
|
|
222
|
+
* Gemini (OpenAI-compatible API wrappers)
|
|
223
|
+
* DeepSeek
|
|
224
|
+
* Any **OpenAI-compatible LLM server**
|
|
225
|
+
|
|
226
|
+
If AI fails or no key exists?
|
|
227
|
+
โจ CT gracefully falls back to manual templates.
|
|
228
|
+
|
|
229
|
+
---
|
|
230
|
+
|
|
231
|
+
## โ
**8. URL Scraper (Headless page scanner)**
|
|
232
|
+
|
|
233
|
+
Given a URL, CT extracts:
|
|
234
|
+
|
|
235
|
+
* Page title
|
|
236
|
+
* Headings
|
|
237
|
+
* Buttons
|
|
238
|
+
* Inputs
|
|
239
|
+
* Basic layout info
|
|
240
|
+
|
|
241
|
+
This helps the LLM generate highly accurate test cases.
|
|
242
|
+
|
|
243
|
+
---
|
|
244
|
+
|
|
245
|
+
## โญ๏ธ CLI Commands Reference
|
|
246
|
+
|
|
247
|
+
Below is every command CT currently supports.
|
|
248
|
+
|
|
249
|
+
---
|
|
250
|
+
|
|
251
|
+
# ๐ฆ **CLI Commands**
|
|
252
|
+
|
|
253
|
+
---
|
|
254
|
+
|
|
255
|
+
## `ct new "<projectName>"`
|
|
256
|
+
|
|
257
|
+
Scaffold a new CementicTest + Playwright project from scratch.
|
|
258
|
+
|
|
259
|
+
**Examples:**
|
|
260
|
+
|
|
261
|
+
```bash
|
|
262
|
+
ct new "Bank"
|
|
263
|
+
ct new "Bank" --no-browsers # Skip browser download
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
What it does:
|
|
267
|
+
|
|
268
|
+
* Installs Playwright
|
|
269
|
+
* Runs browser install
|
|
270
|
+
* Creates POM structure
|
|
271
|
+
* Adds sample pages & test
|
|
272
|
+
* Ready in under 30 seconds
|
|
273
|
+
|
|
274
|
+
---
|
|
275
|
+
|
|
276
|
+
## `ct tc`
|
|
277
|
+
|
|
278
|
+
Interactive test case writer.
|
|
279
|
+
|
|
280
|
+
```bash
|
|
281
|
+
# Interactive mode
|
|
282
|
+
ct tc
|
|
283
|
+
|
|
284
|
+
# Non-interactive mode (CI/Scripting)
|
|
285
|
+
ct tc --feature "Login" --desc "Login page" --count 5
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
Prompts (Interactive):
|
|
289
|
+
|
|
290
|
+
* Feature/page name
|
|
291
|
+
* Optional app description
|
|
292
|
+
* Number of test cases
|
|
293
|
+
|
|
294
|
+
Generates Markdown inside `/cases`.
|
|
295
|
+
|
|
296
|
+
---
|
|
297
|
+
|
|
298
|
+
## `ct tc --ai`
|
|
299
|
+
|
|
300
|
+
Same as above, but uses AI (requires API key):
|
|
301
|
+
|
|
302
|
+
```bash
|
|
303
|
+
ct tc --ai
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
---
|
|
307
|
+
|
|
308
|
+
## `ct tc url <url> --ai`
|
|
309
|
+
|
|
310
|
+
Scrape + AI test case writer.
|
|
311
|
+
|
|
312
|
+
```bash
|
|
313
|
+
ct tc url https://mini-bank.testamplify.com/login --ai
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
This is the most powerful mode.
|
|
317
|
+
|
|
318
|
+
---
|
|
319
|
+
|
|
320
|
+
## `ct normalize <path>`
|
|
321
|
+
|
|
322
|
+
Convert human-readable test cases into machine-readable JSON format.
|
|
323
|
+
|
|
324
|
+
```bash
|
|
325
|
+
ct normalize ./cases
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
Outputs:
|
|
329
|
+
|
|
330
|
+
```
|
|
331
|
+
.cementic/normalized/*.json
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
---
|
|
335
|
+
|
|
336
|
+
## `ct normalize <path> --and-gen --lang ts`
|
|
337
|
+
|
|
338
|
+
Normalize AND generate tests in one step.
|
|
339
|
+
|
|
340
|
+
```bash
|
|
341
|
+
ct normalize ./cases --and-gen --lang ts
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
---
|
|
345
|
+
|
|
346
|
+
## `ct gen --lang ts`
|
|
347
|
+
|
|
348
|
+
Generate Playwright test files from normalized JSON cases.
|
|
349
|
+
|
|
350
|
+
```bash
|
|
351
|
+
ct gen --lang ts
|
|
352
|
+
ct gen --lang ts --out tests/e2e # Custom output directory
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
---
|
|
356
|
+
|
|
357
|
+
## `ct test`
|
|
358
|
+
|
|
359
|
+
Runs Playwright test runner.
|
|
360
|
+
|
|
361
|
+
```bash
|
|
362
|
+
ct test
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
---
|
|
366
|
+
|
|
367
|
+
## `ct flow`
|
|
368
|
+
|
|
369
|
+
**One-Shot Command**: Normalizes cases, generates tests, and runs them in sequence.
|
|
370
|
+
|
|
371
|
+
```bash
|
|
372
|
+
ct flow
|
|
373
|
+
ct flow --lang js
|
|
374
|
+
ct flow --no-run # Normalize & Generate only (skip execution)
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
---
|
|
378
|
+
|
|
379
|
+
## `ct report`
|
|
380
|
+
|
|
381
|
+
Opens the Playwright HTML report in your default browser.
|
|
382
|
+
|
|
383
|
+
```bash
|
|
384
|
+
ct report
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
---
|
|
388
|
+
|
|
389
|
+
## `ct serve`
|
|
390
|
+
|
|
391
|
+
Starts the Allure report server (if Allure is configured).
|
|
392
|
+
|
|
393
|
+
```bash
|
|
394
|
+
ct serve
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
---
|
|
398
|
+
|
|
399
|
+
## `ct ci`
|
|
400
|
+
|
|
401
|
+
Generates a GitHub Actions workflow file (`.github/workflows/cementic.yml`) for CI/CD.
|
|
402
|
+
|
|
403
|
+
```bash
|
|
404
|
+
ct ci
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
---
|
|
408
|
+
|
|
409
|
+
# โ๏ธ Environment Variables
|
|
410
|
+
|
|
411
|
+
| Variable | Description |
|
|
412
|
+
| ----------------- | --------------------------------------- |
|
|
413
|
+
| `CT_LLM_API_KEY` | Primary AI key |
|
|
414
|
+
| `OPENAI_API_KEY` | Secondary AI key |
|
|
415
|
+
| `CT_LLM_MODEL` | Override default model (`gpt-4.1-mini`) |
|
|
416
|
+
| `CT_LLM_BASE_URL` | Custom LLM endpoint |
|
|
417
|
+
| `CT_DEBUG` | Enables verbose logging |
|
|
418
|
+
|
|
419
|
+
---
|
|
420
|
+
|
|
421
|
+
# ๐ Project Structure
|
|
422
|
+
|
|
423
|
+
After running `ct new โMyProjectโ`:
|
|
424
|
+
|
|
425
|
+
```
|
|
426
|
+
project/
|
|
427
|
+
pages/
|
|
428
|
+
login.page.ts
|
|
429
|
+
...
|
|
430
|
+
tests/
|
|
431
|
+
sample.spec.ts
|
|
432
|
+
test-data/
|
|
433
|
+
utils/
|
|
434
|
+
cases/
|
|
435
|
+
.cementic/
|
|
436
|
+
normalized/
|
|
437
|
+
playwright.config.ts
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
---
|
|
441
|
+
|
|
442
|
+
# ๐งฉ Architecture Overview
|
|
443
|
+
|
|
444
|
+
### **Input**
|
|
445
|
+
|
|
446
|
+
* Human test cases (Markdown)
|
|
447
|
+
* AI-generated test cases
|
|
448
|
+
* Scraped UI context
|
|
449
|
+
|
|
450
|
+
### **Processing**
|
|
451
|
+
|
|
452
|
+
1. Normalize (Markdown โ JSON)
|
|
453
|
+
2. Generate POM-based Playwright tests
|
|
454
|
+
3. Maintain test ID prefixes (AUTH-###, DASH-###, etc.)
|
|
455
|
+
|
|
456
|
+
### **Output**
|
|
457
|
+
|
|
458
|
+
* Full Playwright automation suite ready to run
|
|
459
|
+
|
|
460
|
+
---
|
|
461
|
+
|
|
462
|
+
# ๐ Developer Setup (For Internal Development)
|
|
463
|
+
|
|
464
|
+
### Clone & install dependencies
|
|
465
|
+
|
|
466
|
+
```bash
|
|
467
|
+
git clone <repo>
|
|
468
|
+
cd cementic-test
|
|
469
|
+
npm install
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
### Build the CLI
|
|
473
|
+
|
|
474
|
+
```bash
|
|
475
|
+
npm run build
|
|
476
|
+
```
|
|
477
|
+
|
|
478
|
+
### Link locally
|
|
479
|
+
|
|
480
|
+
```bash
|
|
481
|
+
npm link
|
|
482
|
+
```
|
|
483
|
+
|
|
484
|
+
Test globally:
|
|
485
|
+
|
|
486
|
+
```bash
|
|
487
|
+
ct --help
|
|
488
|
+
```
|
|
489
|
+
|
|
490
|
+
---
|
|
491
|
+
|
|
492
|
+
# ๐งช Developer Testing Loop
|
|
493
|
+
|
|
494
|
+
1. Modify code
|
|
495
|
+
2. Run:
|
|
496
|
+
|
|
497
|
+
```
|
|
498
|
+
npm run build && npm link
|
|
499
|
+
```
|
|
500
|
+
|
|
501
|
+
3. In a sample project:
|
|
502
|
+
|
|
503
|
+
```
|
|
504
|
+
mkdir demo && cd demo
|
|
505
|
+
ct new "Shop"
|
|
506
|
+
ct tc url https://example.com/login --ai
|
|
507
|
+
ct normalize ./cases --and-gen --lang ts
|
|
508
|
+
ct test
|
|
509
|
+
```
|
|
510
|
+
|
|
511
|
+
---
|
|
512
|
+
|
|
513
|
+
# ๐ Implementation Notes (For Your Developer)
|
|
514
|
+
|
|
515
|
+
### Key directories:
|
|
516
|
+
|
|
517
|
+
```
|
|
518
|
+
src/
|
|
519
|
+
cli.ts
|
|
520
|
+
commands/
|
|
521
|
+
new.ts
|
|
522
|
+
tc.ts
|
|
523
|
+
normalize.ts
|
|
524
|
+
gen.ts
|
|
525
|
+
test.ts
|
|
526
|
+
core/
|
|
527
|
+
prefix.ts
|
|
528
|
+
normalize.ts
|
|
529
|
+
llm.ts
|
|
530
|
+
scrape.ts
|
|
531
|
+
generator.ts
|
|
532
|
+
templates/
|
|
533
|
+
```
|
|
534
|
+
|
|
535
|
+
### Important details:
|
|
536
|
+
|
|
537
|
+
* **`tc.ts`** manually checks `process.argv` for `--ai`
|
|
538
|
+
(because Commander is inconsistent with subcommands)
|
|
539
|
+
* URL mode scrapes with `scrapePageSummary()`
|
|
540
|
+
* LLM integration is fully isolated inside `core/llm.ts`
|
|
541
|
+
* Test generation happens in `core/generator.ts`
|
|
542
|
+
* Normalization lives in `core/normalize.ts`
|
|
543
|
+
* Pages generator/templates live inside `templates/pages`
|
|
544
|
+
|
|
545
|
+
### Code standards:
|
|
546
|
+
|
|
547
|
+
* TypeScript everywhere
|
|
548
|
+
* ESM modules
|
|
549
|
+
* No external runtime dependencies except Playwright
|
|
550
|
+
* Everything async
|
|
551
|
+
* Clear separation between:
|
|
552
|
+
|
|
553
|
+
* Commands (CLI)
|
|
554
|
+
* Logic (core)
|
|
555
|
+
* Templates (scaffolding)
|
|
556
|
+
* Outputs (.cementic, tests, pages, cases)
|
|
557
|
+
|
|
558
|
+
---
|
|
559
|
+
|
|
560
|
+
# ๐ฆ Release Process
|
|
561
|
+
|
|
562
|
+
We use GitHub Actions for automated releases.
|
|
563
|
+
|
|
564
|
+
### 1. Bump Version
|
|
565
|
+
Update `package.json` version:
|
|
566
|
+
```bash
|
|
567
|
+
npm version patch # or minor/major
|
|
568
|
+
```
|
|
569
|
+
|
|
570
|
+
### 2. Push to Main
|
|
571
|
+
```bash
|
|
572
|
+
git push origin main
|
|
573
|
+
```
|
|
574
|
+
*CI will run tests and build.*
|
|
575
|
+
|
|
576
|
+
### 3. Create Release Tag
|
|
577
|
+
```bash
|
|
578
|
+
git push --tags
|
|
579
|
+
```
|
|
580
|
+
*CI will detect the `v*` tag and automatically publish to NPM.*
|
|
581
|
+
|
|
582
|
+
---
|
|
583
|
+
|
|
584
|
+
# ๐
Roadmap
|
|
585
|
+
|
|
586
|
+
### Phase 1 (Current)
|
|
587
|
+
|
|
588
|
+
โ๏ธ CLI scaffolding
|
|
589
|
+
โ๏ธ AI test case generator
|
|
590
|
+
โ๏ธ URL scraping
|
|
591
|
+
โ๏ธ Normalization pipeline
|
|
592
|
+
โ๏ธ POM test generator
|
|
593
|
+
โ๏ธ Playwright runner wrapper
|
|
594
|
+
|
|
595
|
+
---
|
|
596
|
+
|
|
597
|
+
### Phase 2 (Next)
|
|
598
|
+
|
|
599
|
+
๐ Self-healing locators
|
|
600
|
+
๐ Page synchronizer (`ct update pages`)
|
|
601
|
+
๐ API automation support (`ct api`)
|
|
602
|
+
๐ Test coverage reports
|
|
603
|
+
|
|
604
|
+
---
|
|
605
|
+
|
|
606
|
+
### Phase 3 (Future)
|
|
607
|
+
|
|
608
|
+
๐ CT Desktop App (UI version of CLI)
|
|
609
|
+
๐ VS Code extension
|
|
610
|
+
๐ CI/CD pipeline builder
|
|
611
|
+
๐ Visual assertion generator
|
|
612
|
+
๐ CT Agent (continuous learning on test failures)
|
|
613
|
+
|
|
614
|
+
---
|
|
615
|
+
|
|
616
|
+
# ๐ค Contributing
|
|
617
|
+
|
|
618
|
+
1. Fork the repo
|
|
619
|
+
2. Create a feature branch
|
|
620
|
+
3. Follow code conventions
|
|
621
|
+
4. Build & test locally (`npm link`)
|
|
622
|
+
5. Submit PR# cementic-test
|
|
623
|
+
6. What's Next?
|
|
624
|
+
|
|
625
|
+
We created an org on NPMjs
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/commands/gen.ts
|
|
4
|
+
import { Command } from "commander";
|
|
5
|
+
import fg from "fast-glob";
|
|
6
|
+
import { readFileSync, mkdirSync, writeFileSync } from "fs";
|
|
7
|
+
import { join, basename, relative, resolve } from "path";
|
|
8
|
+
function buildTestTitle(norm) {
|
|
9
|
+
const idPart = norm.id ? norm.id : "";
|
|
10
|
+
const cleanTitle = norm.title || "Untitled";
|
|
11
|
+
const tagSuffix = (norm.tags ?? []).map((t) => `@${t}`).join(" ");
|
|
12
|
+
return [idPart, cleanTitle, tagSuffix].filter(Boolean).join(" ").trim();
|
|
13
|
+
}
|
|
14
|
+
function buildTestBody(norm, relPomImport) {
|
|
15
|
+
const title = buildTestTitle(norm);
|
|
16
|
+
const stepsComment = (norm.steps ?? []).map((s) => `- ${s}`).join("\n // ");
|
|
17
|
+
const expectations = (norm.expected ?? []).map(
|
|
18
|
+
(e) => ` // expect: ${e}
|
|
19
|
+
// TODO: map this to a real assertion using LoginPage`
|
|
20
|
+
).join("\n\n");
|
|
21
|
+
let importPath = relPomImport.replace(/\\/g, "/");
|
|
22
|
+
if (!importPath.startsWith(".")) {
|
|
23
|
+
importPath = `./${importPath}`;
|
|
24
|
+
}
|
|
25
|
+
return `import { test, expect } from '@playwright/test';
|
|
26
|
+
import { LandingPage } from '${importPath}';
|
|
27
|
+
|
|
28
|
+
test('${title}', async ({ page }) => {
|
|
29
|
+
const pageObj = new LandingPage(page);
|
|
30
|
+
|
|
31
|
+
// Steps inferred from case:
|
|
32
|
+
// ${stepsComment || "TODO: no steps detected"}
|
|
33
|
+
|
|
34
|
+
// Example flow (replace with real mapping later):
|
|
35
|
+
await pageObj.goto();
|
|
36
|
+
// await pageObj.login('user@example.com', 'password');
|
|
37
|
+
|
|
38
|
+
${expectations || " // TODO: add assertions with LandingPage"}
|
|
39
|
+
});
|
|
40
|
+
`;
|
|
41
|
+
}
|
|
42
|
+
async function gen(opts) {
|
|
43
|
+
if (opts.lang !== "ts" && opts.lang !== "js") {
|
|
44
|
+
console.error("MVP supports --lang ts and --lang js only for now.");
|
|
45
|
+
process.exit(1);
|
|
46
|
+
}
|
|
47
|
+
const normalized = await fg([".cementic/normalized/*.json", "!.cementic/normalized/_index.json"]);
|
|
48
|
+
mkdirSync(opts.out, { recursive: true });
|
|
49
|
+
const projectRoot = process.cwd();
|
|
50
|
+
const pagesDir = join(projectRoot, "pages");
|
|
51
|
+
const outDir = resolve(projectRoot, opts.out);
|
|
52
|
+
const relPathToPages = relative(outDir, pagesDir);
|
|
53
|
+
const relPomImport = join(relPathToPages, "LandingPage");
|
|
54
|
+
for (const f of normalized) {
|
|
55
|
+
const norm = JSON.parse(readFileSync(f, "utf8"));
|
|
56
|
+
const stem = basename(f).replace(/\.json$/, "");
|
|
57
|
+
const fileStem = stem.replace(/[^\w-]+/g, "-");
|
|
58
|
+
const body = buildTestBody(norm, relPomImport);
|
|
59
|
+
const ext = opts.lang === "js" ? "spec.js" : "spec.ts";
|
|
60
|
+
const outFile = join(opts.out, `${fileStem}.${ext}`);
|
|
61
|
+
writeFileSync(outFile, body);
|
|
62
|
+
}
|
|
63
|
+
console.log(`\u2705 Generated ${normalized.length} POM-style test file(s) \u2192 ${opts.out}`);
|
|
64
|
+
}
|
|
65
|
+
function genCmd() {
|
|
66
|
+
const cmd = new Command("gen").description("Generate Playwright test files from normalized JSON cases").addHelpText("after", `
|
|
67
|
+
Examples:
|
|
68
|
+
$ ct gen --lang ts
|
|
69
|
+
$ ct gen --lang js --out tests/e2e
|
|
70
|
+
`).option("--lang <lang>", "Target language for test files (ts|js)", "ts").option("--out <dir>", "Output directory for generated tests", "tests/generated").action(async (opts) => {
|
|
71
|
+
await gen({ lang: opts.lang, out: opts.out });
|
|
72
|
+
});
|
|
73
|
+
return cmd;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export {
|
|
77
|
+
gen,
|
|
78
|
+
genCmd
|
|
79
|
+
};
|
|
80
|
+
//# sourceMappingURL=chunk-J63TUHIV.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/gen.ts"],"sourcesContent":["import { Command } from 'commander';\nimport fg from 'fast-glob';\nimport { readFileSync, mkdirSync, writeFileSync } from 'node:fs';\nimport { join, basename, relative, resolve } from 'node:path';\n\ntype NormalizedCase = {\n id?: string;\n title: string;\n tags?: string[];\n steps?: string[];\n expected?: string[];\n needs_review?: boolean;\n source?: string;\n};\n\nfunction buildTestTitle(norm: NormalizedCase): string {\n const idPart = norm.id ? norm.id : '';\n const cleanTitle = norm.title || 'Untitled';\n const tagSuffix = (norm.tags ?? []).map(t => `@${t}`).join(' ');\n return [idPart, cleanTitle, tagSuffix].filter(Boolean).join(' ').trim();\n}\n\nfunction buildTestBody(norm: NormalizedCase, relPomImport: string): string {\n const title = buildTestTitle(norm);\n const stepsComment = (norm.steps ?? []).map(s => `- ${s}`).join('\\n // ');\n const expectations = (norm.expected ?? []).map(\n e => ` // expect: ${e}\\n // TODO: map this to a real assertion using LoginPage`\n ).join('\\n\\n');\n\n // Ensure import path starts with ./ or ../\n let importPath = relPomImport.replace(/\\\\/g, '/');\n if (!importPath.startsWith('.')) {\n importPath = `./${importPath}`;\n }\n\n return `import { test, expect } from '@playwright/test';\nimport { LandingPage } from '${importPath}';\n\ntest('${title}', async ({ page }) => {\n const pageObj = new LandingPage(page);\n\n // Steps inferred from case:\n // ${stepsComment || 'TODO: no steps detected'}\n\n // Example flow (replace with real mapping later):\n await pageObj.goto();\n // await pageObj.login('user@example.com', 'password');\n\n${expectations || ' // TODO: add assertions with LandingPage'}\n});\n`;\n}\n\nexport async function gen(opts: { lang: string; out: string }) {\n if (opts.lang !== 'ts' && opts.lang !== 'js') {\n console.error('MVP supports --lang ts and --lang js only for now.');\n process.exit(1);\n }\n\n const normalized = await fg(['.cementic/normalized/*.json', '!.cementic/normalized/_index.json']);\n mkdirSync(opts.out, { recursive: true });\n\n // Calculate relative path from output dir to 'pages/LandingPage'\n // Assumption: project root has 'pages/'\n const projectRoot = process.cwd();\n const pagesDir = join(projectRoot, 'pages');\n const outDir = resolve(projectRoot, opts.out);\n \n // path.relative(from, to)\n const relPathToPages = relative(outDir, pagesDir);\n const relPomImport = join(relPathToPages, 'LandingPage');\n\n for (const f of normalized) {\n const norm = JSON.parse(readFileSync(f, 'utf8')) as NormalizedCase;\n const stem = basename(f).replace(/\\.json$/, '');\n const fileStem = stem.replace(/[^\\w-]+/g, '-');\n\n const body = buildTestBody(norm, relPomImport);\n const ext = opts.lang === 'js' ? 'spec.js' : 'spec.ts';\n const outFile = join(opts.out, `${fileStem}.${ext}`);\n writeFileSync(outFile, body);\n }\n\n console.log(`โ
Generated ${normalized.length} POM-style test file(s) โ ${opts.out}`);\n}\n\nexport function genCmd() {\n const cmd = new Command('gen')\n .description('Generate Playwright test files from normalized JSON cases')\n .addHelpText('after', `\nExamples:\n $ ct gen --lang ts\n $ ct gen --lang js --out tests/e2e\n`)\n .option('--lang <lang>', 'Target language for test files (ts|js)', 'ts')\n .option('--out <dir>', 'Output directory for generated tests', 'tests/generated')\n .action(async (opts) => {\n await gen({ lang: opts.lang, out: opts.out });\n });\n return cmd;\n}"],"mappings":";;;AAAA,SAAS,eAAe;AACxB,OAAO,QAAQ;AACf,SAAS,cAAc,WAAW,qBAAqB;AACvD,SAAS,MAAM,UAAU,UAAU,eAAe;AAYlD,SAAS,eAAe,MAA8B;AACpD,QAAM,SAAS,KAAK,KAAK,KAAK,KAAK;AACnC,QAAM,aAAa,KAAK,SAAS;AACjC,QAAM,aAAa,KAAK,QAAQ,CAAC,GAAG,IAAI,OAAK,IAAI,CAAC,EAAE,EAAE,KAAK,GAAG;AAC9D,SAAO,CAAC,QAAQ,YAAY,SAAS,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG,EAAE,KAAK;AACxE;AAEA,SAAS,cAAc,MAAsB,cAA8B;AACzE,QAAM,QAAQ,eAAe,IAAI;AACjC,QAAM,gBAAgB,KAAK,SAAS,CAAC,GAAG,IAAI,OAAK,KAAK,CAAC,EAAE,EAAE,KAAK,SAAS;AACzE,QAAM,gBAAgB,KAAK,YAAY,CAAC,GAAG;AAAA,IACzC,OAAK,gBAAgB,CAAC;AAAA;AAAA,EACxB,EAAE,KAAK,MAAM;AAGb,MAAI,aAAa,aAAa,QAAQ,OAAO,GAAG;AAChD,MAAI,CAAC,WAAW,WAAW,GAAG,GAAG;AAC/B,iBAAa,KAAK,UAAU;AAAA,EAC9B;AAEA,SAAO;AAAA,+BACsB,UAAU;AAAA;AAAA,QAEjC,KAAK;AAAA;AAAA;AAAA;AAAA,OAIN,gBAAgB,yBAAyB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAM9C,gBAAgB,4CAA4C;AAAA;AAAA;AAG9D;AAEA,eAAsB,IAAI,MAAqC;AAC7D,MAAI,KAAK,SAAS,QAAQ,KAAK,SAAS,MAAM;AAC5C,YAAQ,MAAM,oDAAoD;AAClE,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,QAAM,aAAa,MAAM,GAAG,CAAC,+BAA+B,mCAAmC,CAAC;AAChG,YAAU,KAAK,KAAK,EAAE,WAAW,KAAK,CAAC;AAIvC,QAAM,cAAc,QAAQ,IAAI;AAChC,QAAM,WAAW,KAAK,aAAa,OAAO;AAC1C,QAAM,SAAS,QAAQ,aAAa,KAAK,GAAG;AAG5C,QAAM,iBAAiB,SAAS,QAAQ,QAAQ;AAChD,QAAM,eAAe,KAAK,gBAAgB,aAAa;AAEvD,aAAW,KAAK,YAAY;AAC1B,UAAM,OAAO,KAAK,MAAM,aAAa,GAAG,MAAM,CAAC;AAC/C,UAAM,OAAO,SAAS,CAAC,EAAE,QAAQ,WAAW,EAAE;AAC9C,UAAM,WAAW,KAAK,QAAQ,YAAY,GAAG;AAE7C,UAAM,OAAO,cAAc,MAAM,YAAY;AAC7C,UAAM,MAAM,KAAK,SAAS,OAAO,YAAY;AAC7C,UAAM,UAAU,KAAK,KAAK,KAAK,GAAG,QAAQ,IAAI,GAAG,EAAE;AACnD,kBAAc,SAAS,IAAI;AAAA,EAC7B;AAEA,UAAQ,IAAI,oBAAe,WAAW,MAAM,kCAA6B,KAAK,GAAG,EAAE;AACrF;AAEO,SAAS,SAAS;AACvB,QAAM,MAAM,IAAI,QAAQ,KAAK,EAC1B,YAAY,2DAA2D,EACvE,YAAY,SAAS;AAAA;AAAA;AAAA;AAAA,CAIzB,EACI,OAAO,iBAAiB,0CAA0C,IAAI,EACtE,OAAO,eAAe,wCAAwC,iBAAiB,EAC/E,OAAO,OAAO,SAAS;AACtB,UAAM,IAAI,EAAE,MAAM,KAAK,MAAM,KAAK,KAAK,IAAI,CAAC;AAAA,EAC9C,CAAC;AACH,SAAO;AACT;","names":[]}
|