simple-playwright-framework 0.0.9 → 0.0.10
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 +95 -97
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "simple-playwright-framework",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.10",
|
|
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,68 +142,34 @@ 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
|
-
writeFileSafe(path.join(demoDir, "
|
|
129
|
-
import {
|
|
130
|
-
export class OrangeHRMLogin implements AuthProvider {
|
|
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';
|
|
143
|
-
test('login with Admin user @smoke', async ({ page, envConfig, td }) => {
|
|
144
|
-
await page.goto(envConfig.baseUrl);
|
|
145
|
-
await page.fill('input[name="username"]', td.users.admin.username);
|
|
146
|
-
await page.fill('input[name="password"]', td.users.admin.password);
|
|
147
|
-
await page.click('button[type="submit"]');
|
|
148
|
-
await expect(page).toHaveURL(/dashboard/);
|
|
149
|
-
});
|
|
150
|
-
`);
|
|
151
|
-
|
|
152
|
-
writeFileSafe(path.join(demoDir, "tests/login/login.scenarios.spec.ts"), `import { test, expect, scenarioLoader, initAuthSession } from 'simple-playwright-framework';
|
|
170
|
+
// -------------------- Tests --------------------
|
|
171
|
+
writeFileSafe(path.join(demoDir, "tests/login/login.scenarios.spec.ts"),
|
|
172
|
+
`import { test, expect, scenarioLoader, initAuthSession } from 'simple-playwright-framework';
|
|
153
173
|
import { providerRegistry } from '@demo-project/auth';
|
|
154
174
|
const scenarios = scenarioLoader(__filename);
|
|
155
175
|
test.describe.parallel("Login scenarios", () => {
|
|
@@ -167,74 +187,51 @@ test.describe.parallel("Login scenarios", () => {
|
|
|
167
187
|
});
|
|
168
188
|
`);
|
|
169
189
|
|
|
170
|
-
writeFileSafe(path.join(demoDir, "tests/
|
|
171
|
-
import {
|
|
172
|
-
test('login with Admin user using Auth Storage', async ({ page, envConfig, td }) => {
|
|
173
|
-
await page.goto(envConfig.baseUrl);
|
|
174
|
-
await initAuthSession(page, envConfig.authStorage!, { username: td.users.admin.username, password: td.users.admin.password }, providerRegistry);
|
|
175
|
-
await expect(page).toHaveURL(/dashboard/);
|
|
176
|
-
});
|
|
177
|
-
`);
|
|
190
|
+
writeFileSafe(path.join(demoDir, "tests/filehandling/filehandling.spec.ts"),
|
|
191
|
+
`import { test, expect } from 'simple-playwright-framework';
|
|
178
192
|
|
|
179
|
-
writeFileSafe(path.join(demoDir, "tests/login/login.testrail.spec.ts"), `import { test, expect } from 'simple-playwright-framework';
|
|
180
|
-
test('Login linked to TestRail case C1234', async ({ page, envConfig, testrail }) => {
|
|
181
|
-
await page.goto(envConfig.baseUrl);
|
|
182
|
-
await page.fill('input[name="username"]', 'Admin');
|
|
183
|
-
await page.fill('input[name="password"]', 'admin123');
|
|
184
|
-
await page.click('button[type="submit"]');
|
|
185
|
-
try {
|
|
186
|
-
await expect(page).toHaveURL(/dashboard/);
|
|
187
|
-
await testrail.addResult(1234, 1, "Login passed ✅");
|
|
188
|
-
} catch (err) {
|
|
189
|
-
await testrail.addResult(1234, 5, "Login failed ❌");
|
|
190
|
-
throw err;
|
|
191
|
-
}
|
|
192
|
-
});
|
|
193
|
-
`);
|
|
194
|
-
|
|
195
|
-
// tests/filehandling
|
|
196
|
-
writeFileSafe(path.join(demoDir, "tests/filehandling/filehandling.spec.ts"), `import { test } from 'simple-playwright-framework';
|
|
197
193
|
test("upload and download demo", async ({ page, fileUtils }) => {
|
|
198
194
|
await page.goto("https://the-internet.herokuapp.com/upload");
|
|
199
195
|
await fileUtils.uploadFile("#file-upload", "data/ui/sample.txt");
|
|
200
196
|
await page.click("#file-submit");
|
|
197
|
+
|
|
201
198
|
await page.goto("https://the-internet.herokuapp.com/download");
|
|
202
|
-
const
|
|
199
|
+
const link = page.locator("a[href*='sample.txt']");
|
|
200
|
+
await expect(link).toBeVisible();
|
|
201
|
+
|
|
202
|
+
const downloadedPath = await fileUtils.downloadFile("a[href*='sample.txt']");
|
|
203
203
|
console.log("Downloaded file path:", downloadedPath);
|
|
204
204
|
});
|
|
205
205
|
`);
|
|
206
206
|
|
|
207
|
-
|
|
208
|
-
|
|
207
|
+
writeFileSafe(path.join(demoDir, "tests/api/api.test.ts"),
|
|
208
|
+
`import { test, expect } from 'simple-playwright-framework';
|
|
209
209
|
test('sample API call', async ({ request, envConfig }) => {
|
|
210
|
-
|
|
210
|
+
console.log("API URL: " + envConfig.apiUrl);
|
|
211
|
+
const response = await request.get(\`\${envConfig.apiUrl}/users\`);
|
|
211
212
|
expect(response.status()).toBe(200);
|
|
212
213
|
});
|
|
213
214
|
`);
|
|
214
215
|
|
|
215
|
-
//
|
|
216
|
-
writeFileSafe(path.join(demoDir, "
|
|
217
|
-
|
|
218
|
-
const path = await fileUtils.downloadFile("https://example.com/file.txt");
|
|
219
|
-
console.log("Downloaded:", path);
|
|
220
|
-
});
|
|
221
|
-
`);
|
|
216
|
+
// -------------------- README --------------------
|
|
217
|
+
writeFileSafe(path.join(demoDir, "README.md"),
|
|
218
|
+
`# Demo Project
|
|
222
219
|
|
|
223
|
-
|
|
224
|
-
writeFileSafe(path.join(demoDir, "tests/reporting/testrail.test.ts"), `import { test } from 'simple-playwright-framework';
|
|
225
|
-
test('reporting example', async ({ testrail }) => {
|
|
226
|
-
await testrail.addResult(5678, 1, "Reporting fixture works ✅");
|
|
227
|
-
});
|
|
228
|
-
`);
|
|
220
|
+
This is a scaffolded Playwright demo project using **simple-playwright-framework**.
|
|
229
221
|
|
|
230
|
-
|
|
231
|
-
|
|
222
|
+
## Features
|
|
223
|
+
- ✅ UI login scenarios (success & failure)
|
|
224
|
+
- ✅ API test using jsonplaceholder
|
|
225
|
+
- ✅ File upload & download test with FileUtils
|
|
226
|
+
- ✅ Auth storage example
|
|
232
227
|
|
|
233
|
-
|
|
234
|
-
Run \`npm run
|
|
228
|
+
## Usage
|
|
229
|
+
- Run \`npm run init\` to scaffold the project
|
|
230
|
+
- Run \`npm run test\` to execute all sample tests
|
|
231
|
+
- Run \`npm run build\` to compile TypeScript
|
|
235
232
|
`);
|
|
236
233
|
|
|
237
|
-
// Final step: install deps + build
|
|
234
|
+
// -------------------- Final step: install deps + build --------------------
|
|
238
235
|
try {
|
|
239
236
|
console.log("🚀 Installing dependencies and building demo-project...");
|
|
240
237
|
run("npm install", demoDir);
|
|
@@ -244,3 +241,4 @@ try {
|
|
|
244
241
|
console.error("❌ Init failed:", err.message);
|
|
245
242
|
process.exit(1);
|
|
246
243
|
}
|
|
244
|
+
|