simple-playwright-framework 0.0.9 → 0.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 +3 -2
- package/scripts/init-demo-project.js +110 -60
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "simple-playwright-framework",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.11",
|
|
4
4
|
"description": "A modular Playwright framework with fixtures, loaders, and demo scaffolding.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -40,6 +40,7 @@
|
|
|
40
40
|
"rimraf": "^6.1.2",
|
|
41
41
|
"ts-node": "^10.9.2",
|
|
42
42
|
"tsconfig-paths": "^4.2.0",
|
|
43
|
-
"typescript": "^5.9.3"
|
|
43
|
+
"typescript": "^5.9.3",
|
|
44
|
+
"node-fetch": "^2.6.7"
|
|
44
45
|
}
|
|
45
46
|
}
|
|
@@ -18,7 +18,7 @@ function run(cmd, cwd) {
|
|
|
18
18
|
execSync(cmd, { stdio: "inherit", cwd });
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
// package.json
|
|
21
|
+
// -------------------- package.json --------------------
|
|
22
22
|
writeFileSafe(path.join(demoDir, "package.json"),
|
|
23
23
|
JSON.stringify({
|
|
24
24
|
name: "demo-project",
|
|
@@ -39,7 +39,7 @@ writeFileSafe(path.join(demoDir, "package.json"),
|
|
|
39
39
|
}, null, 2)
|
|
40
40
|
);
|
|
41
41
|
|
|
42
|
-
// tsconfig.json
|
|
42
|
+
// -------------------- tsconfig.json --------------------
|
|
43
43
|
writeFileSafe(path.join(demoDir, "tsconfig.json"),
|
|
44
44
|
JSON.stringify({
|
|
45
45
|
compilerOptions: {
|
|
@@ -52,30 +52,84 @@ writeFileSafe(path.join(demoDir, "tsconfig.json"),
|
|
|
52
52
|
resolveJsonModule: true,
|
|
53
53
|
types: ["@playwright/test", "simple-playwright-framework", "node"],
|
|
54
54
|
baseUrl: ".",
|
|
55
|
-
paths: { "@demo-project/*": ["./*"]
|
|
55
|
+
paths: { "@demo-project/*": ["./*"], "@demo-project/auth": ["auth/index.ts"] },
|
|
56
56
|
outDir: "dist"
|
|
57
57
|
},
|
|
58
58
|
include: ["tests/**/*.ts", "global.d.ts"]
|
|
59
59
|
}, null, 2)
|
|
60
60
|
);
|
|
61
61
|
|
|
62
|
-
// playwright.config.ts
|
|
63
|
-
writeFileSafe(path.join(demoDir, "playwright.config.ts"),
|
|
62
|
+
// -------------------- playwright.config.ts --------------------
|
|
63
|
+
writeFileSafe(path.join(demoDir, "playwright.config.ts"),
|
|
64
|
+
`import { defineConfig } from '@playwright/test';
|
|
64
65
|
export default defineConfig({ testDir: './tests', reporter: [['html']] });
|
|
65
66
|
`);
|
|
66
67
|
|
|
67
|
-
|
|
68
|
-
// config
|
|
68
|
+
// -------------------- environments.json --------------------
|
|
69
69
|
writeFileSafe(path.join(demoDir, "config/environments.json"),
|
|
70
70
|
JSON.stringify({
|
|
71
71
|
defaults: { timeout: 30000, retries: 1, autoLaunch: false },
|
|
72
72
|
dev: { baseUrl: "https://dev.orangehrm.example.com", authStorage: { enabled: true, provider: "OrangeHRMLogin" } },
|
|
73
73
|
qa: { baseUrl: "https://qa.orangehrm.example.com", authStorage: { enabled: true, provider: "OrangeHRMLogin" } },
|
|
74
|
-
prod: { baseUrl: "https://opensource-demo.orangehrmlive.com/", authStorage: { enabled: true, provider: "OrangeHRMLogin" } }
|
|
74
|
+
prod: { baseUrl: "https://opensource-demo.orangehrmlive.com/", apiUrl: "https://jsonplaceholder.typicode.com", authStorage: { enabled: true, provider: "OrangeHRMLogin" } }
|
|
75
75
|
}, null, 2)
|
|
76
76
|
);
|
|
77
77
|
|
|
78
|
-
//
|
|
78
|
+
// -------------------- Auth Provider --------------------
|
|
79
|
+
writeFileSafe(path.join(demoDir, "auth/index.ts"),
|
|
80
|
+
`import { OrangeHRMLogin } from "./orangehrm.login";
|
|
81
|
+
|
|
82
|
+
export const providerRegistry = {
|
|
83
|
+
OrangeHRMLogin,
|
|
84
|
+
};
|
|
85
|
+
`);
|
|
86
|
+
|
|
87
|
+
writeFileSafe(path.join(demoDir, "auth/orangehrm.login.ts"),
|
|
88
|
+
`import { Page } from '@playwright/test';
|
|
89
|
+
import { AuthProvider } from 'simple-playwright-framework';
|
|
90
|
+
export class OrangeHRMLogin implements AuthProvider {
|
|
91
|
+
constructor(private creds: { username: string; password: string }) {}
|
|
92
|
+
async login(page: Page): Promise<void> {
|
|
93
|
+
await page.fill("input[name='username']", this.creds.username);
|
|
94
|
+
await page.fill("input[name='password']", this.creds.password);
|
|
95
|
+
await page.click("button[type='submit']");
|
|
96
|
+
// No unconditional waitForURL here — handled in tests
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
`);
|
|
100
|
+
|
|
101
|
+
// -------------------- FileUtils --------------------
|
|
102
|
+
writeFileSafe(path.join(demoDir, "utils/file-utils.ts"),
|
|
103
|
+
`import { Page } from "@playwright/test";
|
|
104
|
+
import fs from "fs";
|
|
105
|
+
import path from "path";
|
|
106
|
+
|
|
107
|
+
export class FileUtils {
|
|
108
|
+
constructor(private page: Page) {}
|
|
109
|
+
|
|
110
|
+
async uploadFile(selector: string, filePath: string) {
|
|
111
|
+
const absolutePath = path.resolve(filePath);
|
|
112
|
+
if (!fs.existsSync(absolutePath)) {
|
|
113
|
+
throw new Error(\`❌ File not found: \${absolutePath}\`);
|
|
114
|
+
}
|
|
115
|
+
await this.page.setInputFiles(selector, absolutePath);
|
|
116
|
+
console.log(\`✅ Uploaded file: \${absolutePath}\`);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
async downloadFile(selector: string, downloadDir: string = "downloads") {
|
|
120
|
+
const downloadPromise = this.page.waitForEvent("download");
|
|
121
|
+
await this.page.click(selector);
|
|
122
|
+
const download = await downloadPromise;
|
|
123
|
+
|
|
124
|
+
const filePath = path.join(downloadDir, await download.suggestedFilename());
|
|
125
|
+
await download.saveAs(filePath);
|
|
126
|
+
console.log(\`✅ File downloaded to: \${filePath}\`);
|
|
127
|
+
return filePath;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
`);
|
|
131
|
+
|
|
132
|
+
// -------------------- Data --------------------
|
|
79
133
|
writeFileSafe(path.join(demoDir, "data/login/login.json"),
|
|
80
134
|
JSON.stringify({
|
|
81
135
|
prod: {
|
|
@@ -88,58 +142,35 @@ writeFileSafe(path.join(demoDir, "data/login/login.json"),
|
|
|
88
142
|
}
|
|
89
143
|
}, null, 2)
|
|
90
144
|
);
|
|
145
|
+
|
|
91
146
|
writeFileSafe(path.join(demoDir, "data/login/login.scenarios.json"),
|
|
92
147
|
JSON.stringify({
|
|
93
148
|
prod: [
|
|
94
149
|
{ name: "Valid login", url: "https://opensource-demo.orangehrmlive.com/", username: "Admin", password: "admin123", expected: "success", tags: ["smoke"] },
|
|
95
150
|
{ name: "Invalid login", url: "https://opensource-demo.orangehrmlive.com/", username: "WrongUser", password: "WrongPass", expected: "failure", tags: ["negative"] },
|
|
96
|
-
{ name: "Valid login Two", url: "https://opensource-demo.orangehrmlive.com/", username: "
|
|
151
|
+
{ name: "Valid login Two", url: "https://opensource-demo.orangehrmlive.com/", username: "Admin", password: "admin123", expected: "success", tags: ["regression","positive"] }
|
|
97
152
|
]
|
|
98
153
|
}, null, 2)
|
|
99
154
|
);
|
|
155
|
+
|
|
100
156
|
writeFileSafe(path.join(demoDir, "data/login/loginwithauthstorage.json"),
|
|
101
157
|
JSON.stringify({ prod: { users: { admin: { username: "Admin", password: "admin123" } } } }, null, 2)
|
|
102
158
|
);
|
|
103
159
|
|
|
104
|
-
|
|
105
|
-
// -------------------- auth/index.ts --------------------
|
|
106
|
-
writeFileSafe(path.join(demoDir, "auth/index.ts"),
|
|
107
|
-
`import { OrangeHRMLogin } from "./orangehrm.login";
|
|
108
|
-
|
|
109
|
-
export const providerRegistry = {
|
|
110
|
-
OrangeHRMLogin,
|
|
111
|
-
};
|
|
112
|
-
`);
|
|
113
|
-
|
|
114
|
-
// data/api
|
|
115
160
|
writeFileSafe(path.join(demoDir, "data/api/payload.json"),
|
|
116
161
|
JSON.stringify({ createUser: { username: "demoUser", password: "demoPass" } }, null, 2)
|
|
117
162
|
);
|
|
118
163
|
|
|
119
|
-
// data/ui
|
|
120
164
|
writeFileSafe(path.join(demoDir, "data/ui/sample.txt"), "This is a sample file used for upload tests.\n");
|
|
121
165
|
|
|
122
|
-
// storage
|
|
123
166
|
writeFileSafe(path.join(demoDir, "storage/authStorage.json"),
|
|
124
167
|
JSON.stringify({ session: { validityMinutes: 30, provider: "OrangeHRMLogin" } }, null, 2)
|
|
125
168
|
);
|
|
126
169
|
|
|
127
|
-
//
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
constructor(private creds: { username: string; password: string }) {}
|
|
132
|
-
async login(page: Page): Promise<void> {
|
|
133
|
-
await page.fill("input[name='username']", this.creds.username);
|
|
134
|
-
await page.fill("input[name='password']", this.creds.password);
|
|
135
|
-
await page.click("button[type='submit']");
|
|
136
|
-
await page.waitForURL("**/dashboard/**");
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
`);
|
|
140
|
-
|
|
141
|
-
// tests/login
|
|
142
|
-
writeFileSafe(path.join(demoDir, "tests/login/login.test.ts"), `import { test, expect } from 'simple-playwright-framework';
|
|
170
|
+
// -------------------- Tests --------------------
|
|
171
|
+
// Login basic test
|
|
172
|
+
writeFileSafe(path.join(demoDir, "tests/login/login.test.ts"),
|
|
173
|
+
`import { test, expect } from 'simple-playwright-framework';
|
|
143
174
|
test('login with Admin user @smoke', async ({ page, envConfig, td }) => {
|
|
144
175
|
await page.goto(envConfig.baseUrl);
|
|
145
176
|
await page.fill('input[name="username"]', td.users.admin.username);
|
|
@@ -149,7 +180,9 @@ test('login with Admin user @smoke', async ({ page, envConfig, td }) => {
|
|
|
149
180
|
});
|
|
150
181
|
`);
|
|
151
182
|
|
|
152
|
-
|
|
183
|
+
// Login scenarios
|
|
184
|
+
writeFileSafe(path.join(demoDir, "tests/login/login.scenarios.spec.ts"),
|
|
185
|
+
`import { test, expect, scenarioLoader, initAuthSession } from 'simple-playwright-framework';
|
|
153
186
|
import { providerRegistry } from '@demo-project/auth';
|
|
154
187
|
const scenarios = scenarioLoader(__filename);
|
|
155
188
|
test.describe.parallel("Login scenarios", () => {
|
|
@@ -167,7 +200,9 @@ test.describe.parallel("Login scenarios", () => {
|
|
|
167
200
|
});
|
|
168
201
|
`);
|
|
169
202
|
|
|
170
|
-
|
|
203
|
+
// Login with auth storage
|
|
204
|
+
writeFileSafe(path.join(demoDir, "tests/login/loginwithauthstorage.spec.ts"),
|
|
205
|
+
`import { test, expect, initAuthSession } from 'simple-playwright-framework';
|
|
171
206
|
import { providerRegistry } from '@demo-project/auth';
|
|
172
207
|
test('login with Admin user using Auth Storage', async ({ page, envConfig, td }) => {
|
|
173
208
|
await page.goto(envConfig.baseUrl);
|
|
@@ -176,7 +211,9 @@ test('login with Admin user using Auth Storage', async ({ page, envConfig, td })
|
|
|
176
211
|
});
|
|
177
212
|
`);
|
|
178
213
|
|
|
179
|
-
|
|
214
|
+
// Login with TestRail reporting
|
|
215
|
+
writeFileSafe(path.join(demoDir, "tests/login/login.testrail.spec.ts"),
|
|
216
|
+
`import { test, expect } from 'simple-playwright-framework';
|
|
180
217
|
test('Login linked to TestRail case C1234', async ({ page, envConfig, testrail }) => {
|
|
181
218
|
await page.goto(envConfig.baseUrl);
|
|
182
219
|
await page.fill('input[name="username"]', 'Admin');
|
|
@@ -192,46 +229,59 @@ test('Login linked to TestRail case C1234', async ({ page, envConfig, testrail }
|
|
|
192
229
|
});
|
|
193
230
|
`);
|
|
194
231
|
|
|
195
|
-
//
|
|
196
|
-
writeFileSafe(path.join(demoDir, "tests/filehandling/filehandling.spec.ts"),
|
|
232
|
+
// File handling test
|
|
233
|
+
writeFileSafe(path.join(demoDir, "tests/filehandling/filehandling.spec.ts"),
|
|
234
|
+
`import { test, expect } from 'simple-playwright-framework';
|
|
235
|
+
|
|
197
236
|
test("upload and download demo", async ({ page, fileUtils }) => {
|
|
198
237
|
await page.goto("https://the-internet.herokuapp.com/upload");
|
|
199
238
|
await fileUtils.uploadFile("#file-upload", "data/ui/sample.txt");
|
|
200
239
|
await page.click("#file-submit");
|
|
240
|
+
|
|
201
241
|
await page.goto("https://the-internet.herokuapp.com/download");
|
|
202
|
-
const
|
|
242
|
+
const link = page.locator("a[href*='sample.txt']");
|
|
243
|
+
await expect(link).toBeVisible();
|
|
244
|
+
|
|
245
|
+
const downloadedPath = await fileUtils.downloadFile("a[href*='sample.txt']");
|
|
203
246
|
console.log("Downloaded file path:", downloadedPath);
|
|
204
247
|
});
|
|
205
248
|
`);
|
|
206
249
|
|
|
207
|
-
//
|
|
208
|
-
writeFileSafe(path.join(demoDir, "tests/api/api.test.ts"),
|
|
250
|
+
// API test
|
|
251
|
+
writeFileSafe(path.join(demoDir, "tests/api/api.test.ts"),
|
|
252
|
+
`import { test, expect } from 'simple-playwright-framework';
|
|
209
253
|
test('sample API call', async ({ request, envConfig }) => {
|
|
210
|
-
|
|
254
|
+
console.log("API URL: " + envConfig.apiUrl);
|
|
255
|
+
const response = await request.get(\`\${envConfig.apiUrl}/users\`);
|
|
211
256
|
expect(response.status()).toBe(200);
|
|
212
257
|
});
|
|
213
258
|
`);
|
|
214
259
|
|
|
215
|
-
//
|
|
216
|
-
writeFileSafe(path.join(demoDir, "tests/
|
|
217
|
-
|
|
218
|
-
const path = await fileUtils.downloadFile("https://example.com/file.txt");
|
|
219
|
-
console.log("Downloaded:", path);
|
|
220
|
-
});
|
|
221
|
-
`);
|
|
222
|
-
|
|
223
|
-
// tests/reporting
|
|
224
|
-
writeFileSafe(path.join(demoDir, "tests/reporting/testrail.test.ts"), `import { test } from 'simple-playwright-framework';
|
|
260
|
+
// Reporting example
|
|
261
|
+
writeFileSafe(path.join(demoDir, "tests/reporting/testrail.test.ts"),
|
|
262
|
+
`import { test } from 'simple-playwright-framework';
|
|
225
263
|
test('reporting example', async ({ testrail }) => {
|
|
226
264
|
await testrail.addResult(5678, 1, "Reporting fixture works ✅");
|
|
227
265
|
});
|
|
228
266
|
`);
|
|
229
267
|
|
|
230
268
|
// README
|
|
231
|
-
writeFileSafe(path.join(demoDir, "README.md"),
|
|
269
|
+
writeFileSafe(path.join(demoDir, "README.md"),
|
|
270
|
+
`# Demo Project
|
|
232
271
|
|
|
233
272
|
This is a scaffolded Playwright demo project using **simple-playwright-framework**.
|
|
234
|
-
|
|
273
|
+
|
|
274
|
+
## Features
|
|
275
|
+
- ✅ UI login scenarios (success & failure)
|
|
276
|
+
- ✅ API test using jsonplaceholder
|
|
277
|
+
- ✅ File upload & download test with FileUtils
|
|
278
|
+
- ✅ Auth storage example
|
|
279
|
+
- ✅ TestRail reporting example
|
|
280
|
+
|
|
281
|
+
## Usage
|
|
282
|
+
- Run \`npm run init\` to scaffold the project
|
|
283
|
+
- Run \`npm run test\` to execute all sample tests
|
|
284
|
+
- Run \`npm run build\` to compile TypeScript
|
|
235
285
|
`);
|
|
236
286
|
|
|
237
287
|
// Final step: install deps + build
|