agents-cli-automation 1.0.9 → 1.0.11
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/package.json +1 -1
- package/src/templates/playwright-agent-ts.md +59 -734
package/package.json
CHANGED
|
@@ -1,736 +1,61 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
argument-hint: The inputs this agent expects, e.g., "a task to implement" or "a question to answer".
|
|
5
|
-
tools:
|
|
6
|
-
- read
|
|
7
|
-
- create_file
|
|
8
|
-
- apply_patch
|
|
9
|
-
- run_in_terminal
|
|
10
|
-
- file_search
|
|
11
|
-
- grep_search
|
|
12
|
-
- manage_todo_list
|
|
13
|
-
---
|
|
14
|
-
This agent documents and automates reproducing the repository layout, creating a minimal, scalable Playwright-based UI test framework (targeting https://www.saucedemo.com/ by default), and providing recommended developer commands so a new contributor can recreate the workspace and run tests. When to use - When a new contributor needs to scaffold a local copy of this project structure, generate minimal UI test scaffolding (Playwright + page objects + sample tests), and install tooling to run tests and Playwright flows against Saucedemo. Inputs (argument-hint) - task (required): one of scaffold, verify, describe, create-sample-tests. - targetPath (optional): filesystem path where scaffolding should be created. Defaults to repository root. - installDeps (optional boolean): when true, agent will install Node dependencies and Playwright browsers. - force (optional boolean): when true, allow overwriting placeholder files (use with caution). - uiTarget (optional): URL to target for UI tests; defaults to https://www.saucedemo.com/. Capabilities / Behavior - Read the repo layout and create any missing directories listed in the standard layout. - Create placeholder files for missing source files (short header + file path + TODO notes). - Create Playwright scaffolding when requested, including: - a playwright.config.ts sample if missing, - a tests/ui/saucedemo.spec.ts sample test that logs in and asserts inventory load, - a ui/page page-object for the login and inventory pages, - package.json script recommendations for test, test:ui, and install:browsers. - Optionally install Node dependencies and Playwright browsers when installDeps=true. - Run verification commands (npm test, npx playwright test --list, npx playwright test) and return concise logs. Prerequisites - Node.js (v16+) and npm (or pnpm) installed. - Internet access for package installation and Playwright browser download. Representative scaffolded layout
|
|
15
|
-
package.json (sample scripts)
|
|
16
|
-
playwright.config.ts (generated if missing)
|
|
17
|
-
tests/
|
|
18
|
-
ui/
|
|
19
|
-
saucedemo.spec.ts # sample UI test
|
|
20
|
-
api/
|
|
21
|
-
schd-group-create.api.spec.ts
|
|
22
|
-
core/
|
|
23
|
-
api/
|
|
24
|
-
auth/
|
|
25
|
-
db/
|
|
26
|
-
ui/
|
|
27
|
-
page/
|
|
28
|
-
LoginPage.ts
|
|
29
|
-
InventoryPage.ts
|
|
30
|
-
features/
|
|
31
|
-
steps/
|
|
32
|
-
utils/
|
|
33
|
-
readJson.ts
|
|
34
|
-
playwright-report/
|
|
35
|
-
screenshots/
|
|
36
|
-
test-results/
|
|
37
|
-
Scaffold steps (task: scaffold) 1. Validate targetPath exists or create it. 2. Create the repository directory tree (only new directories created). 3. For each file present in the source repo, preserve content. For missing, create placeholders containing a header, responsibilities, and TODO notes. 4. When createSample=true or task=create-sample-tests, add Playwright scaffolding: - playwright.config.ts (simple config using chromium and testDir tests/ui). - tests/ui/saucedemo.spec.ts (sample test: navigate to uiTarget, perform login using standard Saucedemo credentials from sample data, assert inventory list visible). - ui/page/LoginPage.ts and ui/page/InventoryPage.ts page objects. - Update or create package.json scripts: test, test:ui, install:browsers. 5. If installDeps=true, run npm ci (or npm install) then npx playwright install (use --with-deps where appropriate). 6. Run verification: npm run test:ui -- --list or npx playwright test --list and optionally execute the sample test. Suggested commands (PowerShell / cross-platform)
|
|
38
|
-
powershell
|
|
39
|
-
# install dependencies
|
|
40
|
-
npm ci
|
|
41
|
-
# install Playwright browsers
|
|
42
|
-
npx playwright install
|
|
43
|
-
# run unit/api tests
|
|
44
|
-
npm test
|
|
45
|
-
# run Playwright E2E tests
|
|
46
|
-
npm run test:ui
|
|
47
|
-
Sample tests/ui/saucedemo.spec.ts behavior (generated when requested) - Open uiTarget (defaults to https://www.saucedemo.com/). - Use LoginPage to enter standard_user / secret_sauce and submit. - Wait for InventoryPage to display and assert at least one product is visible. Outputs - Created directories and placeholder files in targetPath. - Generated Playwright UI scaffolding and a runnable sample test when requested. - Verification logs for dependency install and sample test runs. - A summary list of placeholders and recommended edits (e.g., secrets, environment overrides). Safety & constraints - The agent will not overwrite existing non-placeholder files unless force=true is set. - The agent will not embed secrets into scaffolded files; secrets must be provided separately or via env vars. Example usages - Scaffold without installing deps: { "task": "scaffold", "installDeps": false } - Scaffold + install deps + create samples: { "task": "scaffold", "installDeps": true, "createSample": true } - Create only sample UI tests: { "task": "create-sample-tests", "targetPath": ".", "uiTarget": "https://www.saucedemo.com/" } - Describe repo: { "task": "describe" } Maintainer notes - Keep the generated playwright.config.ts and sample tests minimal — encourage contributors to migrate tests into the repository's existing structure and page objects. - When adding real credentials, instruct users to use environment variables or a secure secrets store. --- Automation agent specification end. Included file templates (drop-in ready) Below are copy-paste-ready templates for the key files you can generate from this agent to produce a runnable Playwright UI framework targeting https://www.saucedemo.com/. 1) package.json (merge with your existing package.json or use as a template)
|
|
48
|
-
json
|
|
49
|
-
{
|
|
50
|
-
"name": "poc_bbc",
|
|
51
|
-
"version": "1.0.0",
|
|
52
|
-
"type": "commonjs",
|
|
53
|
-
"scripts": {
|
|
54
|
-
"dbtest": "npx playwright test --project=db",
|
|
55
|
-
"uitest": "npx bddgen & npx playwright test --project=ui --headed",
|
|
56
|
-
"test": "npx playwright test",
|
|
57
|
-
"test:ui": "npx playwright test --project=ui-plain",
|
|
58
|
-
"install:browsers": "npx playwright install"
|
|
59
|
-
},
|
|
60
|
-
"devDependencies": {
|
|
61
|
-
"@playwright/test": "^1.58.2",
|
|
62
|
-
"playwright-bdd": "^8.4.2",
|
|
63
|
-
"ts-node": "^10.9.2",
|
|
64
|
-
"typescript": "^5.9.3"
|
|
65
|
-
},
|
|
66
|
-
"dependencies": {
|
|
67
|
-
"dotenv": "^17.2.3",
|
|
68
|
-
"mssql": "^12.2.0"
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
2) playwright.config.ts (the repo already has a BDD config; this snippet adds a plain UI project)
|
|
72
|
-
typescript
|
|
73
|
-
import 'dotenv/config';
|
|
74
|
-
import { defineConfig, devices } from '@playwright/test';
|
|
75
|
-
import { defineBddConfig } from 'playwright-bdd';
|
|
76
|
-
|
|
77
|
-
export const bddConfig = defineBddConfig({
|
|
78
|
-
features: ['tests/ui/features/**/*.feature'],
|
|
79
|
-
steps: ['tests/ui/steps/**/*.steps.ts','tests/fixtures/pages.fixture.ts'],
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
export default defineConfig({
|
|
83
|
-
testDir: './tests',
|
|
84
|
-
timeout: 20 * 1000,
|
|
85
|
-
expect: { timeout: 10 * 1000 },
|
|
86
|
-
retries: process.env.CI ? 1 : 0,
|
|
87
|
-
reporter: [['html', { open: 'never' }], ['list']],
|
|
88
|
-
use: { trace: 'retain-on-failure', screenshot: 'only-on-failure', video: 'retain-on-failure' },
|
|
89
|
-
projects: [
|
|
90
|
-
{
|
|
91
|
-
name: 'ui',
|
|
92
|
-
testDir: './.features-gen',
|
|
93
|
-
testMatch: '**/*.feature.spec.*',
|
|
94
|
-
use: { ...devices['Desktop Chrome'], headless: true, baseURL: process.env.UI_BASE_URL },
|
|
95
|
-
},
|
|
96
|
-
{
|
|
97
|
-
name: 'api',
|
|
98
|
-
testMatch: /.*\.api\.spec\.ts/,
|
|
99
|
-
use: { browserName: undefined, baseURL: process.env.API_BASE_URL, extraHTTPHeaders: { 'Content-Type': 'application/json' } },
|
|
100
|
-
},
|
|
101
|
-
{
|
|
102
|
-
name: 'db',
|
|
103
|
-
testMatch: /.*\.db\.spec\.ts/,
|
|
104
|
-
use: { browserName: undefined },
|
|
105
|
-
},
|
|
106
|
-
// Plain UI tests (non-BDD)
|
|
107
|
-
{
|
|
108
|
-
name: 'ui-plain',
|
|
109
|
-
testDir: './tests/ui',
|
|
110
|
-
use: { ...devices['Desktop Chrome'], headless: true, baseURL: process.env.UI_BASE_URL || 'https://www.saucedemo.com/' },
|
|
111
|
-
},
|
|
112
|
-
],
|
|
113
|
-
});
|
|
114
|
-
3) ui/page/LoginPage.ts (page object)
|
|
115
|
-
typescript
|
|
116
|
-
import { Page } from '@playwright/test';
|
|
117
|
-
|
|
118
|
-
export class LoginPage {
|
|
119
|
-
readonly page: Page;
|
|
120
|
-
constructor(page: Page) { this.page = page; }
|
|
121
|
-
async goto() { await this.page.goto('/'); }
|
|
122
|
-
async login(username: string, password: string) {
|
|
123
|
-
await this.page.fill('#user-name', username);
|
|
124
|
-
await this.page.fill('#password', password);
|
|
125
|
-
await this.page.click('#login-button');
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
4) ui/page/InventoryPage.ts (page object)
|
|
129
|
-
typescript
|
|
130
|
-
import { Page, Locator } from '@playwright/test';
|
|
131
|
-
|
|
132
|
-
export class InventoryPage {
|
|
133
|
-
readonly page: Page;
|
|
134
|
-
readonly items: Locator;
|
|
135
|
-
constructor(page: Page) { this.page = page; this.items = page.locator('.inventory_item'); }
|
|
136
|
-
async isLoaded(): Promise<boolean> { return await this.items.first().isVisible(); }
|
|
137
|
-
getItems(): Locator { return this.items; }
|
|
138
|
-
}
|
|
139
|
-
5) tests/ui/saucedemo.spec.ts (plain Playwright test)
|
|
140
|
-
typescript
|
|
141
|
-
import { test, expect } from '@playwright/test';
|
|
142
|
-
import { LoginPage } from '../../ui/page/LoginPage';
|
|
143
|
-
import { InventoryPage } from '../../ui/page/InventoryPage';
|
|
144
|
-
|
|
145
|
-
test.describe('Saucedemo smoke', () => {
|
|
146
|
-
test('login and inventory visible', async ({ page, baseURL }) => {
|
|
147
|
-
const login = new LoginPage(page);
|
|
148
|
-
const inventory = new InventoryPage(page);
|
|
149
|
-
await page.goto(baseURL || 'https://www.saucedemo.com/');
|
|
150
|
-
await login.login('standard_user', 'secret_sauce');
|
|
151
|
-
await expect(page.locator('.inventory_list')).toBeVisible();
|
|
152
|
-
await expect(inventory.getItems().first()).toBeVisible();
|
|
153
|
-
});
|
|
154
|
-
});
|
|
155
|
-
6) .env.example (environment variables sample)
|
|
156
|
-
text
|
|
157
|
-
UI_BASE_URL=https://www.saucedemo.com/
|
|
158
|
-
API_BASE_URL=http://localhost:3000
|
|
159
|
-
Usage notes - The templates above are ready to paste into files. The agent's scaffold task may create them automatically when createSample=true. - To run locally after creating files:
|
|
160
|
-
powershell
|
|
161
|
-
npm ci
|
|
162
|
-
npm run install:browsers
|
|
163
|
-
npm run test:ui
|
|
164
|
-
- The test uses Saucedemo public credentials: standard_user / secret_sauce. If you want, I can now: (choose one) - Generate these files automatically in the repo (I will create the files listed above). - Or leave this agent file as the canonical template and not modify the filesystem. Repository file list and embedded key file contents Below is a repository file list (captured from the workspace) followed by the full contents of selected key files (UI, tests, core helpers). Use these as drop-in references when running the agent's create/scaffold actions. File list (workspace snapshot):
|
|
165
|
-
c:\poc_bbc\workflows\schd-group\api\schd-group.api.ts
|
|
166
|
-
c:\poc_bbc\workflows\schd-group\invariants\db.invariants.ts
|
|
167
|
-
c:\poc_bbc\workflows\schd-group\invariants\api.invariants.ts
|
|
168
|
-
c:\poc_bbc\workflows\schd-group\invariants\permission.invariants.ts
|
|
169
|
-
c:\poc_bbc\core\permission\permission.types.ts
|
|
170
|
-
c:\poc_bbc\core\permission\permission.schd-group.ts
|
|
171
|
-
c:\poc_bbc\workflows\schd-group\db\schd-group.queries.ts
|
|
172
|
-
c:\poc_bbc\core\auth\roles.ts
|
|
173
|
-
c:\poc_bbc\core\db\queries.ts
|
|
174
|
-
c:\poc_bbc\core\db\connection.ts
|
|
175
|
-
c:\poc_bbc\tsconfig.json
|
|
176
|
-
c:\poc_bbc\core\api\apiClient.ts
|
|
177
|
-
c:\poc_bbc\playwright.config.ts
|
|
178
|
-
c:\poc_bbc\package.json
|
|
179
|
-
c:\poc_bbc\package-lock.json
|
|
180
|
-
c:\poc_bbc\bitbucket-pipelines.yml
|
|
181
|
-
c:\poc_bbc\.gitignore
|
|
182
|
-
c:\poc_bbc\.github\agents\automation.md.agent.md
|
|
183
|
-
c:\poc_bbc\tests\utils\readJson.ts
|
|
184
|
-
c:\poc_bbc\tests\utils\formFiller.ts
|
|
185
|
-
c:\poc_bbc\tests\fixtures\test.fixture.ts
|
|
186
|
-
c:\poc_bbc\tests\fixtures\pages.fixture.ts
|
|
187
|
-
c:\poc_bbc\tests\types\formField.ts
|
|
188
|
-
c:\poc_bbc\tests\ui\steps\scheduling-groups.steps.ts
|
|
189
|
-
c:\poc_bbc\tests\ui\steps\booking.steps.ts
|
|
190
|
-
c:\poc_bbc\tests\ui\features\scheduling-groups.feature
|
|
191
|
-
c:\poc_bbc\tests\ui\features\booking.feature
|
|
192
|
-
c:\poc_bbc\tests\ui\page\HomePage.ts
|
|
193
|
-
c:\poc_bbc\tests\db\01-connection.db.spec.ts
|
|
194
|
-
c:\poc_bbc\tests\api\schd-group-create.api.spec.ts
|
|
195
|
-
c:\poc_bbc\.bitbucket\README.md
|
|
196
|
-
c:\poc_bbc\.bitbucket\pull_request_template.md
|
|
197
|
-
c:\poc_bbc\tests\data\facilityFormData.json
|
|
198
|
-
Embedded key file contents 1) package.json
|
|
199
|
-
json
|
|
200
|
-
{
|
|
201
|
-
"name": "poc_bbc",
|
|
202
|
-
"version": "1.0.0",
|
|
203
|
-
"description": "",
|
|
204
|
-
"main": "index.js",
|
|
205
|
-
"scripts": {
|
|
206
|
-
"dbtest": "npx playwright test --project=db",
|
|
207
|
-
"uitest": "npx bddgen & npx playwright test --project=ui --headed"
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
},
|
|
211
|
-
"keywords": [],
|
|
212
|
-
"author": "",
|
|
213
|
-
"license": "ISC",
|
|
214
|
-
"type": "commonjs",
|
|
215
|
-
"devDependencies": {
|
|
216
|
-
"@playwright/test": "^1.58.2",
|
|
217
|
-
"@types/mssql": "^9.1.9",
|
|
218
|
-
"@types/node": "^25.2.3",
|
|
219
|
-
"playwright-bdd": "^8.4.2",
|
|
220
|
-
"ts-node": "^10.9.2",
|
|
221
|
-
"typescript": "^5.9.3"
|
|
222
|
-
},
|
|
223
|
-
"dependencies": {
|
|
224
|
-
"dotenv": "^17.2.3",
|
|
225
|
-
"mssql": "^12.2.0"
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
2) playwright.config.ts
|
|
229
|
-
typescript
|
|
230
|
-
import 'dotenv/config';
|
|
231
|
-
import { defineConfig, devices } from '@playwright/test';
|
|
232
|
-
import { defineBddConfig } from 'playwright-bdd';
|
|
233
|
-
|
|
234
|
-
// BDD config for UI tests
|
|
235
|
-
export const bddConfig = defineBddConfig({
|
|
236
|
-
features: ['tests/ui/features/**/*.feature'],
|
|
237
|
-
steps: [
|
|
238
|
-
'tests/ui/steps/**/*.steps.ts',
|
|
239
|
-
'tests/fixtures/pages.fixture.ts',
|
|
240
|
-
],
|
|
241
|
-
});
|
|
242
|
-
|
|
243
|
-
export default defineConfig({
|
|
244
|
-
testDir: './tests',
|
|
245
|
-
timeout: 20 * 1000,
|
|
246
|
-
expect: {
|
|
247
|
-
timeout: 10 * 1000,
|
|
248
|
-
},
|
|
249
|
-
retries: process.env.CI ? 1 : 0,
|
|
250
|
-
reporter: [
|
|
251
|
-
['html', { open: 'never' }],
|
|
252
|
-
['list'],
|
|
253
|
-
],
|
|
254
|
-
use: {
|
|
255
|
-
trace: 'retain-on-failure',
|
|
256
|
-
screenshot: 'only-on-failure',
|
|
257
|
-
video: 'retain-on-failure'
|
|
258
|
-
},
|
|
259
|
-
|
|
260
|
-
projects: [
|
|
261
|
-
// =======================
|
|
262
|
-
// UI BDD TESTS
|
|
263
|
-
// =======================
|
|
264
|
-
{
|
|
265
|
-
name: 'ui',
|
|
266
|
-
testDir: './.features-gen', // folder where Playwright-BDD generates .feature.spec.ts
|
|
267
|
-
testMatch: '**/*.feature.spec.*', // match .ts or .js files
|
|
268
|
-
use: {
|
|
269
|
-
...devices['Desktop Chrome'],
|
|
270
|
-
headless: true,
|
|
271
|
-
baseURL: process.env.UI_BASE_URL,
|
|
272
|
-
},
|
|
273
|
-
|
|
274
|
-
},
|
|
275
|
-
|
|
276
|
-
// =======================
|
|
277
|
-
// API TESTS
|
|
278
|
-
// =======================
|
|
279
|
-
{
|
|
280
|
-
name: 'api',
|
|
281
|
-
testMatch: /.*\.api\.spec\.ts/,
|
|
282
|
-
use: {
|
|
283
|
-
browserName: undefined,
|
|
284
|
-
baseURL: process.env.API_BASE_URL,
|
|
285
|
-
extraHTTPHeaders: {
|
|
286
|
-
'Content-Type': 'application/json',
|
|
287
|
-
},
|
|
288
|
-
},
|
|
289
|
-
},
|
|
290
|
-
|
|
291
|
-
// =======================
|
|
292
|
-
// DB TESTS (NO BROWSER)
|
|
293
|
-
// =======================
|
|
294
|
-
{
|
|
295
|
-
name: 'db',
|
|
296
|
-
testMatch: /.*\.db\.spec\.ts/,
|
|
297
|
-
use: {
|
|
298
|
-
browserName: undefined,
|
|
299
|
-
},
|
|
300
|
-
},
|
|
301
|
-
],
|
|
302
|
-
});
|
|
303
|
-
3) core/api/apiClient.ts
|
|
304
|
-
typescript
|
|
305
|
-
import type { APIRequestContext, APIResponse } from "@playwright/test";
|
|
306
|
-
|
|
307
|
-
export const apiGet = (
|
|
308
|
-
request: APIRequestContext,
|
|
309
|
-
url: string,
|
|
310
|
-
): Promise<APIResponse> => {
|
|
311
|
-
return request.get(url);
|
|
312
|
-
};
|
|
313
|
-
|
|
314
|
-
export const apiPost = <T>(
|
|
315
|
-
request: APIRequestContext,
|
|
316
|
-
url: string,
|
|
317
|
-
payload?: T,
|
|
318
|
-
): Promise<APIResponse> => {
|
|
319
|
-
return request.post(url, { data: payload });
|
|
320
|
-
};
|
|
321
|
-
|
|
322
|
-
export const apiPut = <T>(
|
|
323
|
-
request: APIRequestContext,
|
|
324
|
-
url: string,
|
|
325
|
-
payload?: T,
|
|
326
|
-
): Promise<APIResponse> => {
|
|
327
|
-
return request.put(url, { data: payload });
|
|
328
|
-
};
|
|
329
|
-
|
|
330
|
-
export const apiDelete = (
|
|
331
|
-
request: APIRequestContext,
|
|
332
|
-
url: string,
|
|
333
|
-
): Promise<APIResponse> => {
|
|
334
|
-
return request.delete(url);
|
|
335
|
-
};
|
|
336
|
-
4) core/db/connection.ts
|
|
337
|
-
typescript
|
|
338
|
-
import sql from 'mssql';
|
|
339
|
-
|
|
340
|
-
const config: sql.config = {
|
|
341
|
-
server: process.env.DB_HOST!,
|
|
342
|
-
database: process.env.DB_NAME!,
|
|
343
|
-
user: process.env.DB_USER,
|
|
344
|
-
password: process.env.DB_PASSWORD,
|
|
345
|
-
options: {
|
|
346
|
-
trustServerCertificate: true,
|
|
347
|
-
},
|
|
348
|
-
};
|
|
349
|
-
|
|
350
|
-
export async function getDbPool(): Promise<sql.ConnectionPool> {
|
|
351
|
-
return sql.connect(config);
|
|
352
|
-
}
|
|
353
|
-
5) core/db/queries.ts
|
|
354
|
-
typescript
|
|
355
|
-
import type { ConnectionPool } from 'mssql';
|
|
356
|
-
|
|
357
|
-
export async function listTables(db: ConnectionPool) {
|
|
358
|
-
const result = await db.request().query(`
|
|
359
|
-
SELECT TABLE_SCHEMA, TABLE_NAME
|
|
360
|
-
FROM INFORMATION_SCHEMA.TABLES
|
|
361
|
-
WHERE TABLE_TYPE = 'BASE TABLE'
|
|
362
|
-
`);
|
|
363
|
-
|
|
364
|
-
return result.recordset;
|
|
365
|
-
}
|
|
366
|
-
6) core/auth/roles.ts
|
|
367
|
-
typescript
|
|
368
|
-
export enum UserRole {
|
|
369
|
-
SYSTEM_ADMIN = 'SYSTEM_ADMIN',
|
|
370
|
-
AREA_ADMIN = 'AREA_ADMIN',
|
|
371
|
-
VIEW_ONLY = 'VIEW_ONLY',
|
|
372
|
-
}
|
|
373
|
-
7) core/permission/permission.types.ts
|
|
374
|
-
typescript
|
|
375
|
-
export enum Scope {
|
|
376
|
-
ANY = 'ANY',
|
|
377
|
-
OWN_AREA = 'OWN_AREA',
|
|
378
|
-
NONE = 'NONE',
|
|
379
|
-
}
|
|
380
|
-
8) core/permission/permission.schd-group.ts
|
|
381
|
-
typescript
|
|
382
|
-
import { UserRole } from '../auth/roles';
|
|
383
|
-
import { Scope } from './permission.types';
|
|
384
|
-
|
|
385
|
-
export type SchedulingGroupPermissions = {
|
|
386
|
-
view: Scope;
|
|
387
|
-
create: Scope;
|
|
388
|
-
edit: Scope;
|
|
389
|
-
delete: Scope;
|
|
390
|
-
};
|
|
391
|
-
|
|
392
|
-
export const schedulingGroupPermissions: Record<
|
|
393
|
-
UserRole,
|
|
394
|
-
SchedulingGroupPermissions
|
|
395
|
-
> = {
|
|
396
|
-
[UserRole.SYSTEM_ADMIN]: {
|
|
397
|
-
view: Scope.ANY,
|
|
398
|
-
create: Scope.ANY,
|
|
399
|
-
edit: Scope.ANY,
|
|
400
|
-
delete: Scope.ANY,
|
|
401
|
-
},
|
|
402
|
-
|
|
403
|
-
[UserRole.AREA_ADMIN]: {
|
|
404
|
-
view: Scope.OWN_AREA,
|
|
405
|
-
create: Scope.OWN_AREA,
|
|
406
|
-
edit: Scope.OWN_AREA,
|
|
407
|
-
delete: Scope.NONE,
|
|
408
|
-
},
|
|
409
|
-
|
|
410
|
-
[UserRole.VIEW_ONLY]: {
|
|
411
|
-
view: Scope.OWN_AREA,
|
|
412
|
-
create: Scope.NONE,
|
|
413
|
-
edit: Scope.NONE,
|
|
414
|
-
delete: Scope.NONE,
|
|
415
|
-
},
|
|
416
|
-
};
|
|
417
|
-
9) workflows/schd-group/api/schd-group.api.ts
|
|
418
|
-
typescript
|
|
419
|
-
import { APIRequestContext } from '@playwright/test';
|
|
420
|
-
import {
|
|
421
|
-
apiGet,
|
|
422
|
-
apiPost,
|
|
423
|
-
apiPut,
|
|
424
|
-
apiDelete,
|
|
425
|
-
} from '../../../core/api/apiClient';
|
|
426
|
-
|
|
427
|
-
export function createSchedulingGroup(
|
|
428
|
-
api: APIRequestContext,
|
|
429
|
-
payload: {
|
|
430
|
-
area: string;
|
|
431
|
-
groupName: string;
|
|
432
|
-
allocationsMenu?: boolean;
|
|
433
|
-
notes?: string;
|
|
434
|
-
}
|
|
435
|
-
) {
|
|
436
|
-
return apiPost(api, '/scheduling-groups', payload);
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
export function editSchedulingGroup(
|
|
440
|
-
api: APIRequestContext,
|
|
441
|
-
id: number,
|
|
442
|
-
payload: {
|
|
443
|
-
area?: string;
|
|
444
|
-
groupName?: string;
|
|
445
|
-
allocationsMenu?: boolean;
|
|
446
|
-
notes?: string;
|
|
447
|
-
}
|
|
448
|
-
) {
|
|
449
|
-
return apiPut(api, `/scheduling-groups/${id}`, payload);
|
|
450
|
-
}
|
|
451
|
-
|
|
452
|
-
export function deleteSchedulingGroup(
|
|
453
|
-
api: APIRequestContext,
|
|
454
|
-
id: number
|
|
455
|
-
) {
|
|
456
|
-
return apiDelete(api, `/scheduling-groups/${id}`);
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
export function listSchedulingGroups(
|
|
460
|
-
api: APIRequestContext
|
|
461
|
-
) {
|
|
462
|
-
return apiGet(api, '/scheduling-groups');
|
|
463
|
-
}
|
|
464
|
-
10) workflows/schd-group/db/schd-group.queries.ts
|
|
465
|
-
typescript
|
|
466
|
-
import sql from 'mssql';
|
|
467
|
-
|
|
468
|
-
export class SchedulingGroupQueries {
|
|
469
|
-
static async getByName(
|
|
470
|
-
db: sql.ConnectionPool,
|
|
471
|
-
name: string
|
|
472
|
-
) {
|
|
473
|
-
const result = await db
|
|
474
|
-
.request()
|
|
475
|
-
.input('name', sql.VarChar, name)
|
|
476
|
-
.query(`
|
|
477
|
-
SELECT *
|
|
478
|
-
FROM scheduling_groups
|
|
479
|
-
WHERE scheduling_group_name = @name
|
|
480
|
-
`);
|
|
481
|
-
|
|
482
|
-
return result.recordset[0];
|
|
483
|
-
}
|
|
484
|
-
|
|
485
|
-
static async getById(
|
|
486
|
-
db: sql.ConnectionPool,
|
|
487
|
-
id: number
|
|
488
|
-
) {
|
|
489
|
-
const result = await db
|
|
490
|
-
.request()
|
|
491
|
-
.input('id', sql.Int, id)
|
|
492
|
-
.query(`
|
|
493
|
-
SELECT *
|
|
494
|
-
FROM scheduling_groups
|
|
495
|
-
WHERE id = @id
|
|
496
|
-
`);
|
|
497
|
-
|
|
498
|
-
return result.recordset[0];
|
|
499
|
-
}
|
|
500
|
-
|
|
501
|
-
static async exists(
|
|
502
|
-
db: sql.ConnectionPool,
|
|
503
|
-
name: string
|
|
504
|
-
): Promise<boolean> {
|
|
505
|
-
const record = await this.getByName(db, name);
|
|
506
|
-
return !!record;
|
|
507
|
-
}
|
|
508
|
-
|
|
509
|
-
static async listByArea(
|
|
510
|
-
db: sql.ConnectionPool,
|
|
511
|
-
area: string
|
|
512
|
-
) {
|
|
513
|
-
const result = await db
|
|
514
|
-
.request()
|
|
515
|
-
.input('area', sql.VarChar, area)
|
|
516
|
-
.query(`
|
|
517
|
-
SELECT *
|
|
518
|
-
FROM scheduling_groups
|
|
519
|
-
WHERE area = @area
|
|
520
|
-
`);
|
|
521
|
-
|
|
522
|
-
return result.recordset;
|
|
523
|
-
}
|
|
1
|
+
name: Playwright UI Testing - TypeScript (current repo)
|
|
2
|
+
description: Snapshot and quick guide for the Playwright + TypeScript + BDD setup present in this repository.
|
|
3
|
+
argument-hint: "(no args)"
|
|
524
4
|
|
|
525
|
-
|
|
526
|
-
db: sql.ConnectionPool,
|
|
527
|
-
groupId: number
|
|
528
|
-
) {
|
|
529
|
-
const result = await db
|
|
530
|
-
.request()
|
|
531
|
-
.input('id', sql.Int, groupId)
|
|
532
|
-
.query(`
|
|
533
|
-
SELECT *
|
|
534
|
-
FROM scheduling_group_history
|
|
535
|
-
WHERE scheduling_group_id = @id
|
|
536
|
-
ORDER BY amended_date DESC
|
|
537
|
-
`);
|
|
538
|
-
|
|
539
|
-
return result.recordset;
|
|
540
|
-
}
|
|
541
|
-
}
|
|
542
|
-
11) tests/fixtures/pages.fixture.ts
|
|
543
|
-
typescript
|
|
544
|
-
import { test as bddTest } from 'playwright-bdd';
|
|
545
|
-
import { expect } from '@playwright/test';
|
|
546
|
-
import { HomePage } from '../ui/page/HomePage';
|
|
547
|
-
|
|
548
|
-
export type PageFixtures = {
|
|
549
|
-
homePage: HomePage;
|
|
550
|
-
};
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
export const test = bddTest.extend<PageFixtures>({
|
|
554
|
-
homePage: async ({ page }, use) => {
|
|
555
|
-
const homePage = new HomePage(page);
|
|
556
|
-
await use(homePage);
|
|
557
|
-
},
|
|
558
|
-
});
|
|
559
|
-
|
|
560
|
-
export { expect };
|
|
561
|
-
12) tests/fixtures/test.fixture.ts
|
|
562
|
-
typescript
|
|
563
|
-
import {
|
|
564
|
-
test as base,
|
|
565
|
-
expect,
|
|
566
|
-
request,
|
|
567
|
-
APIRequestContext,
|
|
568
|
-
} from '@playwright/test';
|
|
569
|
-
import sql from 'mssql';
|
|
570
|
-
import { getDbPool } from '../../core/db/connection';
|
|
571
|
-
|
|
572
|
-
type TestFixtures = {
|
|
573
|
-
apiAsSystemAdmin: APIRequestContext;
|
|
574
|
-
apiAsAreaAdmin: APIRequestContext;
|
|
575
|
-
db: sql.ConnectionPool;
|
|
576
|
-
};
|
|
577
|
-
|
|
578
|
-
export const test = base.extend<TestFixtures>({
|
|
579
|
-
apiAsSystemAdmin: async ({}, use) => {
|
|
580
|
-
const api = await request.newContext({
|
|
581
|
-
baseURL: process.env.API_BASE_URL,
|
|
582
|
-
storageState: 'storage/system-admin.json',
|
|
583
|
-
});
|
|
584
|
-
|
|
585
|
-
await use(api);
|
|
586
|
-
await api.dispose();
|
|
587
|
-
},
|
|
588
|
-
|
|
589
|
-
apiAsAreaAdmin: async ({}, use) => {
|
|
590
|
-
const api = await request.newContext({
|
|
591
|
-
baseURL: process.env.API_BASE_URL,
|
|
592
|
-
storageState: 'storage/area-admin.json',
|
|
593
|
-
});
|
|
594
|
-
|
|
595
|
-
await use(api);
|
|
596
|
-
await api.dispose();
|
|
597
|
-
},
|
|
598
|
-
|
|
599
|
-
db: async ({}, use) => {
|
|
600
|
-
const pool = await getDbPool();
|
|
601
|
-
await use(pool);
|
|
602
|
-
await pool.close();
|
|
603
|
-
},
|
|
604
|
-
});
|
|
605
|
-
|
|
606
|
-
export { expect };
|
|
607
|
-
13) tests/ui/steps/booking.steps.ts
|
|
608
|
-
typescript
|
|
609
|
-
import { createBdd } from 'playwright-bdd';
|
|
610
|
-
import {test} from '@fixtures/pages.fixture'
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
const { Given, When, Then } = createBdd(test);
|
|
614
|
-
|
|
615
|
-
Given('user opens the Allocate application', async ({ homePage }) => {
|
|
616
|
-
await homePage.open();
|
|
617
|
-
await homePage.isBbcMenuLoaded();
|
|
618
|
-
|
|
619
|
-
});
|
|
620
|
-
When('user create new facility', async ({homePage}) => {
|
|
621
|
-
|
|
622
|
-
await homePage.createFacility()
|
|
623
|
-
|
|
624
|
-
await homePage.verifyFacilityAdded()
|
|
625
|
-
|
|
626
|
-
await homePage.assertViewFacility()
|
|
627
|
-
|
|
628
|
-
await homePage.deleteFacility()
|
|
629
|
-
|
|
630
|
-
});
|
|
631
|
-
14) tests/ui/steps/scheduling-groups.steps.ts
|
|
632
|
-
typescript
|
|
633
|
-
|
|
634
|
-
import { createBdd } from 'playwright-bdd';
|
|
635
|
-
import { test,expect } from '@fixtures/pages.fixture';
|
|
636
|
-
|
|
637
|
-
const { Given, When, Then } = createBdd(test);
|
|
638
|
-
|
|
639
|
-
Given('user switches to System Admin role', async ({homePage}) => {
|
|
640
|
-
await homePage.open();
|
|
641
|
-
const isBbcMenuLoaded = await homePage.isBbcMenuLoaded();
|
|
642
|
-
expect(isBbcMenuLoaded).toBe(true);
|
|
643
|
-
});
|
|
644
|
-
|
|
645
|
-
// When('user navigates to Scheduling Groups page', async ({homePage}) => {
|
|
646
|
-
// // From: tests\ui\features\scheduling-groups.feature:16:5
|
|
647
|
-
// });
|
|
648
|
-
|
|
649
|
-
// When('user creates a scheduling group {string} in {string} with allocations menu {string}', async ({}, arg: string, arg1: string, arg2: string) => {
|
|
650
|
-
// // Step: And user creates a scheduling group "Auto_SystemAdmin_" in "Manchester" with allocations menu "Yes"
|
|
651
|
-
// // From: tests\ui\features\scheduling-groups.feature:17:5
|
|
652
|
-
// });
|
|
653
|
-
|
|
654
|
-
// Then('user can see the new scheduling group in the list', async ({}) => {
|
|
655
|
-
// // Step: Then user can see the new scheduling group in the list
|
|
656
|
-
// // From: tests\ui\features\scheduling-groups.feature:18:5
|
|
657
|
-
// });
|
|
658
|
-
15) tests/ui/features/booking.feature
|
|
659
|
-
feature
|
|
660
|
-
@smoke
|
|
661
|
-
Feature: Booking navigation
|
|
662
|
-
|
|
663
|
-
Scenario: Navigate to Facility Catalogue
|
|
664
|
-
Given user opens the Allocate application
|
|
665
|
-
When user create new facility
|
|
666
|
-
16) tests/ui/features/scheduling-groups.feature
|
|
667
|
-
feature
|
|
668
|
-
@smoke @scheduling-groups
|
|
669
|
-
Feature: Scheduling Groups Management
|
|
670
|
-
|
|
671
|
-
@system-admin
|
|
672
|
-
Scenario: System Admin - Create a new Scheduling Group in any area
|
|
673
|
-
Given user opens the Allocate application
|
|
674
|
-
And user switches to System Admin role
|
|
675
|
-
When user navigates to Scheduling Groups page
|
|
676
|
-
And user creates a scheduling group "Auto_SystemAdmin_" in "Area"
|
|
677
|
-
Then user can see the new scheduling group in the list
|
|
678
|
-
17) tests/ui/page/HomePage.ts (already present in repo)
|
|
679
|
-
typescript
|
|
680
|
-
<content from existing file - see repo for full source>
|
|
681
|
-
18) tests/api/schd-group-create.api.spec.ts
|
|
682
|
-
typescript
|
|
683
|
-
import { test, expect } from "../../tests/fixtures/test.fixture";
|
|
684
|
-
import { createSchedulingGroup } from "../../workflows/schd-group/api/schd-group.api";
|
|
685
|
-
import { SchedulingGroupQueries } from "../../workflows/schd-group/db/schd-group.queries";
|
|
686
|
-
import { assertGroupExists } from "../../workflows/schd-group/invariants/db.invariants";
|
|
687
|
-
|
|
688
|
-
test("System Admin can create Scheduling Group in any Area", async ({apiAsSystemAdmin,db}) => {
|
|
689
|
-
const payload = {
|
|
690
|
-
area: "Manchester",
|
|
691
|
-
groupName: `Auto_${Date.now()}`,
|
|
692
|
-
};
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
//api
|
|
696
|
-
const res = await createSchedulingGroup(apiAsSystemAdmin, payload);
|
|
697
|
-
expect(res.status()).toBe(201);
|
|
698
|
-
|
|
699
|
-
const record = await SchedulingGroupQueries.getByName(db, payload.groupName);
|
|
700
|
-
|
|
701
|
-
//db
|
|
702
|
-
assertGroupExists(record);
|
|
703
|
-
});
|
|
704
|
-
|
|
705
|
-
test("Scheduling Group Name is mandatory", async ({ apiAsSystemAdmin }) => {
|
|
706
|
-
const res = await apiAsSystemAdmin.post("/scheduling-groups", {
|
|
707
|
-
data: { area: "London" },
|
|
708
|
-
});
|
|
709
|
-
|
|
710
|
-
expect(res.status()).toBe(400);
|
|
711
|
-
});
|
|
712
|
-
19) tests/db/01-connection.db.spec.ts
|
|
713
|
-
typescript
|
|
714
|
-
import { test, expect } from '../../tests/fixtures/test.fixture';
|
|
715
|
-
import { listTables } from '../../core/db/queries';
|
|
716
|
-
|
|
717
|
-
test('Tables exist', async ({ db }) => {
|
|
718
|
-
const tables = await listTables(db);
|
|
719
|
-
expect(tables.length).toBeGreaterThan(0);
|
|
720
|
-
});
|
|
721
|
-
20) tests/utils/readJson.ts
|
|
722
|
-
typescript
|
|
723
|
-
import fs from 'fs';
|
|
724
|
-
import path from 'path';
|
|
725
|
-
import { FormField } from '../types/formField';
|
|
5
|
+
---
|
|
726
6
|
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
7
|
+
# Playwright + TypeScript (BDD-capable) — repo snapshot
|
|
8
|
+
|
|
9
|
+
This file documents the current Playwright + TypeScript testing scaffold in the repository and explains how the BDD workflow is wired right now.
|
|
10
|
+
|
|
11
|
+
**Key points (current state)**
|
|
12
|
+
- Playwright config exports a BDD config and a standard config: see [playwright.config.ts](playwright.config.ts).
|
|
13
|
+
- Feature files live under `tests/features` (example: [tests/features/login.feature](tests/features/login.feature)).
|
|
14
|
+
- Generated BDD test output (from Playwright-BDD / generator) appears under `.features-gen` (example: [.features-gen/tests/features/login.feature.spec.js](.features-gen/tests/features/login.feature.spec.js)).
|
|
15
|
+
- Fixtures are defined in [tests/fixtures/base.fixture.ts](tests/fixtures/base.fixture.ts). The repository uses the `playwright-bdd` test extension so steps can access fixtures like `loginPage`.
|
|
16
|
+
- Step definitions live in [tests/steps](tests/steps). Example: [tests/steps/loginSteps.ts](tests/steps/loginSteps.ts) — it uses `createBdd(test)` from `playwright-bdd` and registers Given/When/Then steps that operate on the `loginPage` fixture.
|
|
17
|
+
- TypeScript path aliases are configured in [tsconfig.json](tsconfig.json) for convenience (e.g. `@steps/*`, `@pages/*`, `@fixtures/*`).
|
|
18
|
+
|
|
19
|
+
Files to inspect quickly
|
|
20
|
+
- Playwright config: [playwright.config.ts](playwright.config.ts)
|
|
21
|
+
- TS config / aliases: [tsconfig.json](tsconfig.json)
|
|
22
|
+
- Main fixture: [tests/fixtures/base.fixture.ts](tests/fixtures/base.fixture.ts)
|
|
23
|
+
- Steps: [tests/steps/loginSteps.ts](tests/steps/loginSteps.ts)
|
|
24
|
+
- Feature: [tests/features/login.feature](tests/features/login.feature)
|
|
25
|
+
- Generated spec: [.features-gen/tests/features/login.feature.spec.js](.features-gen/tests/features/login.feature.spec.js)
|
|
26
|
+
- Package scripts: [package.json](package.json)
|
|
27
|
+
|
|
28
|
+
How the BDD flow works here
|
|
29
|
+
- Edit or add Gherkin features in `tests/features/*.feature` and step implementations in `tests/steps/*.ts`.
|
|
30
|
+
- Generate Playwright specs from features/steps with either Playwright-BDD's generator or a local generator (if present). Common commands:
|
|
31
|
+
- Use the Playwright-BDD generator (fetches CLI via npx):
|
|
32
|
+
```bash
|
|
33
|
+
npx bddgen
|
|
34
|
+
```
|
|
35
|
+
- Or run a local generator script if your `package.json` defines one (check `package.json` for `generate:bdd`).
|
|
36
|
+
- Generated specs are written to `.features-gen` (this repo currently contains generated files under `.features-gen/tests/features/`). Those generated specs import the repository fixtures and call `Given/When/Then` using the BDD test helpers.
|
|
37
|
+
|
|
38
|
+
Run the UI BDD tests
|
|
39
|
+
```bash
|
|
40
|
+
# install deps (first time)
|
|
41
|
+
npm install
|
|
42
|
+
npx playwright install chromium
|
|
43
|
+
|
|
44
|
+
# generate specs (use either bddgen or local generator)
|
|
45
|
+
npx bddgen
|
|
46
|
+
# or (if present) npm run generate:bdd
|
|
47
|
+
|
|
48
|
+
# run UI project (headed)
|
|
49
|
+
npx playwright test --project=ui --headed
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Notes & tips
|
|
53
|
+
- If `npx bddgen` is used it will read `bddConfig` exported from [playwright.config.ts](playwright.config.ts) (the `features` and `steps` globs) and will output generated `.feature.spec.*` files into the configured location.
|
|
54
|
+
- The generated specs reference the repository fixtures (so keep `tests/fixtures/base.fixture.ts` exports stable).
|
|
55
|
+
- If TypeScript path aliases are used, ensure editors and build tooling pick up `tsconfig.json` aliases.
|
|
56
|
+
- If you want me to update any generated-spec import style (e.g. prefer `.ts` vs `.js`, or use path aliases inside generator output), tell me which style you prefer and I will patch the generator and re-generate specs.
|
|
57
|
+
|
|
58
|
+
If you'd like, I can now:
|
|
59
|
+
- Run `npx bddgen` and then `npx playwright test --project=ui --headed` and show the test output, or
|
|
60
|
+
- Adjust where the `ui` project looks for generated specs (e.g. change `testDir` to `tests/.features-gen`), or
|
|
61
|
+
- Update the generator output to use TypeScript aliases for cleaner imports.
|