simple-playwright-framework 0.0.8 → 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 +96 -87
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",
|
|
@@ -26,7 +26,7 @@ writeFileSafe(path.join(demoDir, "package.json"),
|
|
|
26
26
|
private: true,
|
|
27
27
|
scripts: {
|
|
28
28
|
init: "node ../framework/scripts/init-demo-project.js",
|
|
29
|
-
clean: "rimraf dist tsconfig.tsbuildinfo",
|
|
29
|
+
clean: "npx rimraf dist tsconfig.tsbuildinfo",
|
|
30
30
|
build: "tsc --build --force",
|
|
31
31
|
test: "playwright test"
|
|
32
32
|
},
|
|
@@ -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,29 +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
|
+
// -------------------- environments.json --------------------
|
|
68
69
|
writeFileSafe(path.join(demoDir, "config/environments.json"),
|
|
69
70
|
JSON.stringify({
|
|
70
71
|
defaults: { timeout: 30000, retries: 1, autoLaunch: false },
|
|
71
72
|
dev: { baseUrl: "https://dev.orangehrm.example.com", authStorage: { enabled: true, provider: "OrangeHRMLogin" } },
|
|
72
73
|
qa: { baseUrl: "https://qa.orangehrm.example.com", authStorage: { enabled: true, provider: "OrangeHRMLogin" } },
|
|
73
|
-
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" } }
|
|
74
75
|
}, null, 2)
|
|
75
76
|
);
|
|
76
77
|
|
|
77
|
-
//
|
|
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 --------------------
|
|
78
133
|
writeFileSafe(path.join(demoDir, "data/login/login.json"),
|
|
79
134
|
JSON.stringify({
|
|
80
135
|
prod: {
|
|
@@ -87,58 +142,34 @@ writeFileSafe(path.join(demoDir, "data/login/login.json"),
|
|
|
87
142
|
}
|
|
88
143
|
}, null, 2)
|
|
89
144
|
);
|
|
145
|
+
|
|
90
146
|
writeFileSafe(path.join(demoDir, "data/login/login.scenarios.json"),
|
|
91
147
|
JSON.stringify({
|
|
92
148
|
prod: [
|
|
93
149
|
{ name: "Valid login", url: "https://opensource-demo.orangehrmlive.com/", username: "Admin", password: "admin123", expected: "success", tags: ["smoke"] },
|
|
94
150
|
{ name: "Invalid login", url: "https://opensource-demo.orangehrmlive.com/", username: "WrongUser", password: "WrongPass", expected: "failure", tags: ["negative"] },
|
|
95
|
-
{ 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"] }
|
|
96
152
|
]
|
|
97
153
|
}, null, 2)
|
|
98
154
|
);
|
|
155
|
+
|
|
99
156
|
writeFileSafe(path.join(demoDir, "data/login/loginwithauthstorage.json"),
|
|
100
157
|
JSON.stringify({ prod: { users: { admin: { username: "Admin", password: "admin123" } } } }, null, 2)
|
|
101
158
|
);
|
|
102
159
|
|
|
103
|
-
// data/api
|
|
104
160
|
writeFileSafe(path.join(demoDir, "data/api/payload.json"),
|
|
105
161
|
JSON.stringify({ createUser: { username: "demoUser", password: "demoPass" } }, null, 2)
|
|
106
162
|
);
|
|
107
163
|
|
|
108
|
-
// data/ui
|
|
109
164
|
writeFileSafe(path.join(demoDir, "data/ui/sample.txt"), "This is a sample file used for upload tests.\n");
|
|
110
165
|
|
|
111
|
-
// storage
|
|
112
166
|
writeFileSafe(path.join(demoDir, "storage/authStorage.json"),
|
|
113
167
|
JSON.stringify({ session: { validityMinutes: 30, provider: "OrangeHRMLogin" } }, null, 2)
|
|
114
168
|
);
|
|
115
169
|
|
|
116
|
-
//
|
|
117
|
-
writeFileSafe(path.join(demoDir, "
|
|
118
|
-
import {
|
|
119
|
-
export class OrangeHRMLogin implements AuthProvider {
|
|
120
|
-
constructor(private creds: { username: string; password: string }) {}
|
|
121
|
-
async login(page: Page): Promise<void> {
|
|
122
|
-
await page.fill("input[name='username']", this.creds.username);
|
|
123
|
-
await page.fill("input[name='password']", this.creds.password);
|
|
124
|
-
await page.click("button[type='submit']");
|
|
125
|
-
await page.waitForURL("**/dashboard/**");
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
`);
|
|
129
|
-
|
|
130
|
-
// tests/login
|
|
131
|
-
writeFileSafe(path.join(demoDir, "tests/login/login.test.ts"), `import { test, expect } from 'simple-playwright-framework';
|
|
132
|
-
test('login with Admin user @smoke', async ({ page, envConfig, td }) => {
|
|
133
|
-
await page.goto(envConfig.baseUrl);
|
|
134
|
-
await page.fill('input[name="username"]', td.users.admin.username);
|
|
135
|
-
await page.fill('input[name="password"]', td.users.admin.password);
|
|
136
|
-
await page.click('button[type="submit"]');
|
|
137
|
-
await expect(page).toHaveURL(/dashboard/);
|
|
138
|
-
});
|
|
139
|
-
`);
|
|
140
|
-
|
|
141
|
-
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';
|
|
142
173
|
import { providerRegistry } from '@demo-project/auth';
|
|
143
174
|
const scenarios = scenarioLoader(__filename);
|
|
144
175
|
test.describe.parallel("Login scenarios", () => {
|
|
@@ -156,74 +187,51 @@ test.describe.parallel("Login scenarios", () => {
|
|
|
156
187
|
});
|
|
157
188
|
`);
|
|
158
189
|
|
|
159
|
-
writeFileSafe(path.join(demoDir, "tests/
|
|
160
|
-
import {
|
|
161
|
-
test('login with Admin user using Auth Storage', async ({ page, envConfig, td }) => {
|
|
162
|
-
await page.goto(envConfig.baseUrl);
|
|
163
|
-
await initAuthSession(page, envConfig.authStorage!, { username: td.users.admin.username, password: td.users.admin.password }, providerRegistry);
|
|
164
|
-
await expect(page).toHaveURL(/dashboard/);
|
|
165
|
-
});
|
|
166
|
-
`);
|
|
190
|
+
writeFileSafe(path.join(demoDir, "tests/filehandling/filehandling.spec.ts"),
|
|
191
|
+
`import { test, expect } from 'simple-playwright-framework';
|
|
167
192
|
|
|
168
|
-
writeFileSafe(path.join(demoDir, "tests/login/login.testrail.spec.ts"), `import { test, expect } from 'simple-playwright-framework';
|
|
169
|
-
test('Login linked to TestRail case C1234', async ({ page, envConfig, testrail }) => {
|
|
170
|
-
await page.goto(envConfig.baseUrl);
|
|
171
|
-
await page.fill('input[name="username"]', 'Admin');
|
|
172
|
-
await page.fill('input[name="password"]', 'admin123');
|
|
173
|
-
await page.click('button[type="submit"]');
|
|
174
|
-
try {
|
|
175
|
-
await expect(page).toHaveURL(/dashboard/);
|
|
176
|
-
await testrail.addResult(1234, 1, "Login passed ✅");
|
|
177
|
-
} catch (err) {
|
|
178
|
-
await testrail.addResult(1234, 5, "Login failed ❌");
|
|
179
|
-
throw err;
|
|
180
|
-
}
|
|
181
|
-
});
|
|
182
|
-
`);
|
|
183
|
-
|
|
184
|
-
// tests/filehandling
|
|
185
|
-
writeFileSafe(path.join(demoDir, "tests/filehandling/filehandling.spec.ts"), `import { test } from 'simple-playwright-framework/fixtures';
|
|
186
193
|
test("upload and download demo", async ({ page, fileUtils }) => {
|
|
187
194
|
await page.goto("https://the-internet.herokuapp.com/upload");
|
|
188
195
|
await fileUtils.uploadFile("#file-upload", "data/ui/sample.txt");
|
|
189
196
|
await page.click("#file-submit");
|
|
197
|
+
|
|
190
198
|
await page.goto("https://the-internet.herokuapp.com/download");
|
|
191
|
-
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']");
|
|
192
203
|
console.log("Downloaded file path:", downloadedPath);
|
|
193
204
|
});
|
|
194
205
|
`);
|
|
195
206
|
|
|
196
|
-
|
|
197
|
-
|
|
207
|
+
writeFileSafe(path.join(demoDir, "tests/api/api.test.ts"),
|
|
208
|
+
`import { test, expect } from 'simple-playwright-framework';
|
|
198
209
|
test('sample API call', async ({ request, envConfig }) => {
|
|
199
|
-
|
|
210
|
+
console.log("API URL: " + envConfig.apiUrl);
|
|
211
|
+
const response = await request.get(\`\${envConfig.apiUrl}/users\`);
|
|
200
212
|
expect(response.status()).toBe(200);
|
|
201
213
|
});
|
|
202
214
|
`);
|
|
203
215
|
|
|
204
|
-
//
|
|
205
|
-
writeFileSafe(path.join(demoDir, "
|
|
206
|
-
|
|
207
|
-
const path = await fileUtils.downloadFile("https://example.com/file.txt");
|
|
208
|
-
console.log("Downloaded:", path);
|
|
209
|
-
});
|
|
210
|
-
`);
|
|
216
|
+
// -------------------- README --------------------
|
|
217
|
+
writeFileSafe(path.join(demoDir, "README.md"),
|
|
218
|
+
`# Demo Project
|
|
211
219
|
|
|
212
|
-
|
|
213
|
-
writeFileSafe(path.join(demoDir, "tests/reporting/testrail.test.ts"), `import { test } from 'simple-playwright-framework';
|
|
214
|
-
test('reporting example', async ({ testrail }) => {
|
|
215
|
-
await testrail.addResult(5678, 1, "Reporting fixture works ✅");
|
|
216
|
-
});
|
|
217
|
-
`);
|
|
220
|
+
This is a scaffolded Playwright demo project using **simple-playwright-framework**.
|
|
218
221
|
|
|
219
|
-
|
|
220
|
-
|
|
222
|
+
## Features
|
|
223
|
+
- ✅ UI login scenarios (success & failure)
|
|
224
|
+
- ✅ API test using jsonplaceholder
|
|
225
|
+
- ✅ File upload & download test with FileUtils
|
|
226
|
+
- ✅ Auth storage example
|
|
221
227
|
|
|
222
|
-
|
|
223
|
-
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
|
|
224
232
|
`);
|
|
225
233
|
|
|
226
|
-
// Final step: install deps + build
|
|
234
|
+
// -------------------- Final step: install deps + build --------------------
|
|
227
235
|
try {
|
|
228
236
|
console.log("🚀 Installing dependencies and building demo-project...");
|
|
229
237
|
run("npm install", demoDir);
|
|
@@ -233,3 +241,4 @@ try {
|
|
|
233
241
|
console.error("❌ Init failed:", err.message);
|
|
234
242
|
process.exit(1);
|
|
235
243
|
}
|
|
244
|
+
|