simple-playwright-framework 0.0.16 → 0.0.18
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/dist/fixtures/data.fixture.js +1 -1
- package/dist/fixtures/index.d.ts +1 -0
- package/dist/fixtures/index.js +12 -2
- package/dist/fixtures/projectConfig.fixture.d.ts +6 -0
- package/dist/fixtures/projectConfig.fixture.js +10 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +3 -1
- package/dist/loaders/projectConfig.loader.d.ts +9 -0
- package/dist/loaders/projectConfig.loader.js +41 -0
- package/dist/types/auth.d.ts +3 -0
- package/dist/types/env.d.ts +1 -0
- package/dist/utils/auth-session/initApiAuthSession.d.ts +20 -0
- package/dist/utils/auth-session/initApiAuthSession.js +49 -0
- package/dist/utils/auth-session/initAuthSession.d.ts +10 -0
- package/dist/utils/auth-session/initAuthSession.js +44 -23
- package/dist/utils/auth-session/resolveProvider.d.ts +13 -0
- package/dist/utils/auth-session/resolveProvider.js +17 -0
- package/dist/utils/auth-session/restoreSession.d.ts +14 -0
- package/dist/utils/auth-session/restoreSession.js +36 -0
- package/dist/utils/auth-session/storagePath.d.ts +6 -0
- package/dist/utils/auth-session/storagePath.js +6 -0
- package/dist/utils/auth-session/validateStore.d.ts +13 -0
- package/dist/utils/auth-session/validateStore.js +26 -3
- package/package.json +1 -1
|
@@ -10,7 +10,7 @@ exports.dataFixture = {
|
|
|
10
10
|
let td;
|
|
11
11
|
try {
|
|
12
12
|
td = (0, data_loader_1.loadTestData)(testInfo, envName);
|
|
13
|
-
console.log("Loaded test data:", td, "Type:", Array.isArray(td) ? "array" : typeof td);
|
|
13
|
+
//console.log("Loaded test data:", td, "Type:", Array.isArray(td) ? "array" : typeof td);
|
|
14
14
|
}
|
|
15
15
|
catch (err) {
|
|
16
16
|
console.error(`❌ loadTestData threw for env '${envName}':`, err);
|
package/dist/fixtures/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Page } from "@playwright/test";
|
|
2
2
|
import { Fixtures } from "../types/fixtures";
|
|
3
3
|
export declare const test: import("@playwright/test").TestType<import("@playwright/test").PlaywrightTestArgs & import("@playwright/test").PlaywrightTestOptions & Fixtures & {
|
|
4
|
+
pc: Record<string, any>;
|
|
4
5
|
authStore: (page: Page, creds: {
|
|
5
6
|
username: string;
|
|
6
7
|
password: string;
|
package/dist/fixtures/index.js
CHANGED
|
@@ -1,4 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
// ════════════════════════════════════════════════════════════════
|
|
3
|
+
// framework/src/fixtures/index.ts
|
|
4
|
+
//
|
|
5
|
+
// MODIFIED — added projectConfigFixture alongside existing fixtures.
|
|
6
|
+
// Only this block is new:
|
|
7
|
+
// ...projectConfigFixture,
|
|
8
|
+
// Everything else is unchanged from your original file.
|
|
9
|
+
// ════════════════════════════════════════════════════════════════
|
|
2
10
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
11
|
if (k2 === undefined) k2 = k;
|
|
4
12
|
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
@@ -19,13 +27,15 @@ const test_1 = require("@playwright/test");
|
|
|
19
27
|
const envConfig_fixture_1 = require("./envConfig.fixture");
|
|
20
28
|
const data_fixture_1 = require("./data.fixture");
|
|
21
29
|
const testrail_fixture_1 = require("./testrail.fixture");
|
|
22
|
-
const initAuthSession_1 = require("../utils/auth-session/initAuthSession");
|
|
23
30
|
const file_fixture_1 = require("./file.fixture");
|
|
31
|
+
const projectConfig_fixture_1 = require("./projectConfig.fixture"); // ← NEW
|
|
32
|
+
const initAuthSession_1 = require("../utils/auth-session/initAuthSession");
|
|
24
33
|
exports.test = test_1.test.extend({
|
|
25
34
|
...envConfig_fixture_1.envConfigFixture,
|
|
26
35
|
...data_fixture_1.dataFixture,
|
|
27
36
|
...testrail_fixture_1.testrailFixture,
|
|
28
37
|
...file_fixture_1.fileFixture,
|
|
38
|
+
...projectConfig_fixture_1.projectConfigFixture, // ← NEW
|
|
29
39
|
authStore: async ({ envConfig }, use) => {
|
|
30
40
|
await use(async (page, creds, providerRegistry) => {
|
|
31
41
|
if (!envConfig.authStorage) {
|
|
@@ -37,4 +47,4 @@ exports.test = test_1.test.extend({
|
|
|
37
47
|
});
|
|
38
48
|
var test_2 = require("@playwright/test");
|
|
39
49
|
Object.defineProperty(exports, "expect", { enumerable: true, get: function () { return test_2.expect; } });
|
|
40
|
-
__exportStar(require("../loaders/scenario.loader"), exports); //
|
|
50
|
+
__exportStar(require("../loaders/scenario.loader"), exports); // ← NEW
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.projectConfigFixture = void 0;
|
|
4
|
+
const projectConfig_loader_1 = require("../loaders/projectConfig.loader");
|
|
5
|
+
exports.projectConfigFixture = {
|
|
6
|
+
pc: async ({ page }, use) => {
|
|
7
|
+
const config = (0, projectConfig_loader_1.loadProjectConfig)();
|
|
8
|
+
await use(config);
|
|
9
|
+
},
|
|
10
|
+
};
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { initAuthSession } from "./utils/auth-session/initAuthSession";
|
|
2
|
+
export { initApiAuthSession } from "./utils/auth-session/initApiAuthSession";
|
|
2
3
|
export { test, expect } from "./fixtures/index";
|
|
3
4
|
export { scenarioLoader } from "./loaders/scenario.loader";
|
|
4
5
|
export { loadConfig } from "./loaders/envConfig.loader";
|
|
@@ -7,4 +8,4 @@ export { envConfigFixture } from "./fixtures/envConfig.fixture";
|
|
|
7
8
|
export { dataFixture } from "./fixtures/data.fixture";
|
|
8
9
|
export { fileFixture } from "./fixtures/file.fixture";
|
|
9
10
|
export { testrailFixture } from "./fixtures/testrail.fixture";
|
|
10
|
-
export type { AuthProvider, AuthStorageConfig } from "./types/auth";
|
|
11
|
+
export type { AuthProvider, ApiAuthProvider, AuthStorageConfig } from "./types/auth";
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.testrailFixture = exports.fileFixture = exports.dataFixture = exports.envConfigFixture = exports.FileUtils = exports.loadConfig = exports.scenarioLoader = exports.expect = exports.test = exports.initAuthSession = void 0;
|
|
3
|
+
exports.testrailFixture = exports.fileFixture = exports.dataFixture = exports.envConfigFixture = exports.FileUtils = exports.loadConfig = exports.scenarioLoader = exports.expect = exports.test = exports.initApiAuthSession = exports.initAuthSession = void 0;
|
|
4
4
|
var initAuthSession_1 = require("./utils/auth-session/initAuthSession");
|
|
5
5
|
Object.defineProperty(exports, "initAuthSession", { enumerable: true, get: function () { return initAuthSession_1.initAuthSession; } });
|
|
6
|
+
var initApiAuthSession_1 = require("./utils/auth-session/initApiAuthSession");
|
|
7
|
+
Object.defineProperty(exports, "initApiAuthSession", { enumerable: true, get: function () { return initApiAuthSession_1.initApiAuthSession; } });
|
|
6
8
|
var index_1 = require("./fixtures/index");
|
|
7
9
|
Object.defineProperty(exports, "test", { enumerable: true, get: function () { return index_1.test; } });
|
|
8
10
|
Object.defineProperty(exports, "expect", { enumerable: true, get: function () { return index_1.expect; } });
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Loads and returns the contents of config/projectConfig.json
|
|
3
|
+
* as a plain object. The shape is defined by each project —
|
|
4
|
+
* the framework imposes no type constraints here.
|
|
5
|
+
*
|
|
6
|
+
* @returns Plain object from projectConfig.json
|
|
7
|
+
* @throws If the file is missing or contains invalid JSON
|
|
8
|
+
*/
|
|
9
|
+
export declare function loadProjectConfig(): Record<string, any>;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// ════════════════════════════════════════════════════════════════
|
|
3
|
+
// framework/src/loaders/projectConfig.loader.ts
|
|
4
|
+
//
|
|
5
|
+
// Loads projectConfig.json from the consuming project's
|
|
6
|
+
// config/ directory. Follows the exact same pattern as
|
|
7
|
+
// envConfig.loader.ts — flat JSON, no env nesting.
|
|
8
|
+
//
|
|
9
|
+
// projectConfig.json is for project-wide constants that are
|
|
10
|
+
// not environment-specific (threshold, schema paths, etc).
|
|
11
|
+
// Anything env-specific belongs in environments.json instead.
|
|
12
|
+
// ════════════════════════════════════════════════════════════════
|
|
13
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
14
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.loadProjectConfig = loadProjectConfig;
|
|
18
|
+
const fs_1 = __importDefault(require("fs"));
|
|
19
|
+
const path_1 = __importDefault(require("path"));
|
|
20
|
+
/**
|
|
21
|
+
* Loads and returns the contents of config/projectConfig.json
|
|
22
|
+
* as a plain object. The shape is defined by each project —
|
|
23
|
+
* the framework imposes no type constraints here.
|
|
24
|
+
*
|
|
25
|
+
* @returns Plain object from projectConfig.json
|
|
26
|
+
* @throws If the file is missing or contains invalid JSON
|
|
27
|
+
*/
|
|
28
|
+
function loadProjectConfig() {
|
|
29
|
+
const configPath = path_1.default.join(process.cwd(), "config", "projectConfig.json");
|
|
30
|
+
if (!fs_1.default.existsSync(configPath)) {
|
|
31
|
+
throw new Error(`❌ projectConfig.json not found at ${configPath}\n` +
|
|
32
|
+
` Create config/projectConfig.json in your project root.`);
|
|
33
|
+
}
|
|
34
|
+
const raw = fs_1.default.readFileSync(configPath, "utf-8");
|
|
35
|
+
try {
|
|
36
|
+
return JSON.parse(raw);
|
|
37
|
+
}
|
|
38
|
+
catch (e) {
|
|
39
|
+
throw new Error(`❌ projectConfig.json contains invalid JSON at ${configPath}\n${e}`);
|
|
40
|
+
}
|
|
41
|
+
}
|
package/dist/types/auth.d.ts
CHANGED
|
@@ -2,6 +2,9 @@ import { Page } from "@playwright/test";
|
|
|
2
2
|
export interface AuthProvider {
|
|
3
3
|
login(page: Page): Promise<void>;
|
|
4
4
|
}
|
|
5
|
+
export interface ApiAuthProvider {
|
|
6
|
+
getToken(request: any): Promise<string>;
|
|
7
|
+
}
|
|
5
8
|
export interface AuthStorageConfig {
|
|
6
9
|
enabled: boolean;
|
|
7
10
|
validityMinutes: number;
|
package/dist/types/env.d.ts
CHANGED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { ApiAuthProvider, AuthStorageConfig } from "../../types/auth";
|
|
2
|
+
/**
|
|
3
|
+
* Manages API token authentication with optional token caching.
|
|
4
|
+
*
|
|
5
|
+
* Flow:
|
|
6
|
+
* 1. If storage disabled → call getToken() directly, no caching
|
|
7
|
+
* 2. If valid cached token exists → return it, skip login call
|
|
8
|
+
* 3. If no valid token → call getToken(), save to file, return token
|
|
9
|
+
*
|
|
10
|
+
* Storage format: { token: "...", savedAt: 1234567890 }
|
|
11
|
+
*
|
|
12
|
+
* @returns JWT token string ready to use in Authorization header
|
|
13
|
+
*/
|
|
14
|
+
export declare function initApiAuthSession(request: any, authStorage: AuthStorageConfig | undefined, creds: {
|
|
15
|
+
username: string;
|
|
16
|
+
password: string;
|
|
17
|
+
}, providerRegistry: Record<string, new (creds: {
|
|
18
|
+
username: string;
|
|
19
|
+
password: string;
|
|
20
|
+
}) => ApiAuthProvider>): Promise<string>;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.initApiAuthSession = initApiAuthSession;
|
|
7
|
+
const fs_1 = __importDefault(require("fs"));
|
|
8
|
+
const storagePath_1 = require("./storagePath");
|
|
9
|
+
const validateStore_1 = require("./validateStore");
|
|
10
|
+
const resolveProvider_1 = require("./resolveProvider");
|
|
11
|
+
/**
|
|
12
|
+
* Manages API token authentication with optional token caching.
|
|
13
|
+
*
|
|
14
|
+
* Flow:
|
|
15
|
+
* 1. If storage disabled → call getToken() directly, no caching
|
|
16
|
+
* 2. If valid cached token exists → return it, skip login call
|
|
17
|
+
* 3. If no valid token → call getToken(), save to file, return token
|
|
18
|
+
*
|
|
19
|
+
* Storage format: { token: "...", savedAt: 1234567890 }
|
|
20
|
+
*
|
|
21
|
+
* @returns JWT token string ready to use in Authorization header
|
|
22
|
+
*/
|
|
23
|
+
async function initApiAuthSession(request, authStorage, creds, providerRegistry) {
|
|
24
|
+
const ProviderClass = (0, resolveProvider_1.resolveProvider)(authStorage?.provider ?? "default", providerRegistry);
|
|
25
|
+
const authProvider = new ProviderClass(creds);
|
|
26
|
+
// ── Storage disabled → get token directly ────────────────────
|
|
27
|
+
if (!authStorage?.enabled) {
|
|
28
|
+
console.log("[Framework] API auth storage disabled — performing direct login");
|
|
29
|
+
return authProvider.getToken(request);
|
|
30
|
+
}
|
|
31
|
+
const { validityMinutes, provider } = authStorage;
|
|
32
|
+
const envName = process.env.TEST_ENV || "default";
|
|
33
|
+
const storagePath = (0, storagePath_1.getStoragePath)(provider, envName, creds.username);
|
|
34
|
+
// ── Valid cached token exists → return it ────────────────────
|
|
35
|
+
if ((0, validateStore_1.isAuthStoreValid)(storagePath, validityMinutes)) {
|
|
36
|
+
const saved = JSON.parse(fs_1.default.readFileSync(storagePath, "utf-8"));
|
|
37
|
+
console.log(`[Framework] ✅ Using cached API token for: ${creds.username}`);
|
|
38
|
+
return saved.token;
|
|
39
|
+
}
|
|
40
|
+
// ── No valid token → fresh login + save ──────────────────────
|
|
41
|
+
console.log("[Framework] Performing fresh API login...");
|
|
42
|
+
const token = await authProvider.getToken(request);
|
|
43
|
+
fs_1.default.writeFileSync(storagePath, JSON.stringify({
|
|
44
|
+
token,
|
|
45
|
+
savedAt: Date.now(),
|
|
46
|
+
}, null, 2));
|
|
47
|
+
console.log(`[Framework] New API token cached: ${storagePath}`);
|
|
48
|
+
return token;
|
|
49
|
+
}
|
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
import { Page } from "@playwright/test";
|
|
2
2
|
import { AuthProvider, AuthStorageConfig } from "../../types/auth";
|
|
3
|
+
/**
|
|
4
|
+
* Manages UI authentication with optional session storage.
|
|
5
|
+
*
|
|
6
|
+
* Flow:
|
|
7
|
+
* 1. If storage disabled → login directly, no caching
|
|
8
|
+
* 2. If valid stored session exists → restore it, skip login
|
|
9
|
+
* 3. If no valid session → perform fresh login, save session
|
|
10
|
+
*
|
|
11
|
+
* Supports both localStorage token apps (Nexus) and cookie-based apps.
|
|
12
|
+
*/
|
|
3
13
|
export declare function initAuthSession(page: Page, authStorage: AuthStorageConfig | undefined, creds: {
|
|
4
14
|
username: string;
|
|
5
15
|
password: string;
|
|
@@ -1,41 +1,62 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
6
|
exports.initAuthSession = initAuthSession;
|
|
7
|
+
const fs_1 = __importDefault(require("fs"));
|
|
4
8
|
const storagePath_1 = require("./storagePath");
|
|
5
9
|
const validateStore_1 = require("./validateStore");
|
|
10
|
+
const resolveProvider_1 = require("./resolveProvider");
|
|
11
|
+
const restoreSession_1 = require("./restoreSession");
|
|
12
|
+
/**
|
|
13
|
+
* Manages UI authentication with optional session storage.
|
|
14
|
+
*
|
|
15
|
+
* Flow:
|
|
16
|
+
* 1. If storage disabled → login directly, no caching
|
|
17
|
+
* 2. If valid stored session exists → restore it, skip login
|
|
18
|
+
* 3. If no valid session → perform fresh login, save session
|
|
19
|
+
*
|
|
20
|
+
* Supports both localStorage token apps (Nexus) and cookie-based apps.
|
|
21
|
+
*/
|
|
6
22
|
async function initAuthSession(page, authStorage, creds, providerRegistry) {
|
|
23
|
+
const ProviderClass = (0, resolveProvider_1.resolveProvider)(authStorage?.provider ?? "default", providerRegistry);
|
|
24
|
+
const authProvider = new ProviderClass(creds);
|
|
25
|
+
// ── Storage disabled → login directly ────────────────────────
|
|
7
26
|
if (!authStorage?.enabled) {
|
|
8
|
-
console.log("[Framework] Auth storage disabled");
|
|
9
|
-
const ProviderClass = providerRegistry[authStorage?.provider ?? "OrangeHRMLogin"];
|
|
10
|
-
const authProvider = new ProviderClass(creds);
|
|
27
|
+
console.log("[Framework] Auth storage disabled — performing direct login");
|
|
11
28
|
await authProvider.login(page);
|
|
12
29
|
return;
|
|
13
30
|
}
|
|
14
31
|
const { validityMinutes, provider } = authStorage;
|
|
15
32
|
const envName = process.env.TEST_ENV || "default";
|
|
16
33
|
const storagePath = (0, storagePath_1.getStoragePath)(provider, envName, creds.username);
|
|
17
|
-
|
|
18
|
-
if (!ProviderClass)
|
|
19
|
-
throw new Error(`[Framework] Unknown provider: ${provider}`);
|
|
20
|
-
const authProvider = new ProviderClass(creds);
|
|
21
|
-
let needsLogin = true;
|
|
34
|
+
// ── Valid session exists → restore it ────────────────────────
|
|
22
35
|
if ((0, validateStore_1.isAuthStoreValid)(storagePath, validityMinutes)) {
|
|
23
|
-
console.log(`[Framework]
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
if (!page.url().includes("/auth/login")) {
|
|
28
|
-
console.log(`[Framework] Reusing valid auth store`);
|
|
29
|
-
needsLogin = false;
|
|
30
|
-
}
|
|
31
|
-
else {
|
|
32
|
-
console.log("[Framework] Auth store rejected, will re-login...");
|
|
33
|
-
}
|
|
36
|
+
console.log(`[Framework] Restoring valid auth store: ${storagePath}`);
|
|
37
|
+
await (0, restoreSession_1.restoreSession)(page, storagePath);
|
|
38
|
+
console.log(`[Framework] ✅ Session restored from storage`);
|
|
39
|
+
return;
|
|
34
40
|
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
41
|
+
// ── No valid session → fresh login + save ────────────────────
|
|
42
|
+
console.log("[Framework] Performing fresh login...");
|
|
43
|
+
await authProvider.login(page);
|
|
44
|
+
// Save token + user from localStorage if present (token-based apps)
|
|
45
|
+
const saved = await page.evaluate(() => ({
|
|
46
|
+
token: localStorage.getItem("token"),
|
|
47
|
+
user: localStorage.getItem("user"),
|
|
48
|
+
}));
|
|
49
|
+
if (saved.token) {
|
|
50
|
+
// Token-based app — save token + user
|
|
51
|
+
fs_1.default.writeFileSync(storagePath, JSON.stringify({
|
|
52
|
+
token: saved.token,
|
|
53
|
+
user: saved.user ? JSON.parse(saved.user) : null,
|
|
54
|
+
savedAt: Date.now(),
|
|
55
|
+
}, null, 2));
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
// Cookie-based app — save full Playwright storageState
|
|
38
59
|
await page.context().storageState({ path: storagePath });
|
|
39
|
-
console.log(`[Framework] New auth store created: ${storagePath}`);
|
|
40
60
|
}
|
|
61
|
+
console.log(`[Framework] New auth store created: ${storagePath}`);
|
|
41
62
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Looks up a provider class from the registry by name.
|
|
3
|
+
* Throws a clear error if the provider is not registered.
|
|
4
|
+
*
|
|
5
|
+
* Used by both initAuthSession (UI) and initApiAuthSession (API).
|
|
6
|
+
*/
|
|
7
|
+
export declare function resolveProvider<T>(providerName: string, providerRegistry: Record<string, new (creds: {
|
|
8
|
+
username: string;
|
|
9
|
+
password: string;
|
|
10
|
+
}) => T>): new (creds: {
|
|
11
|
+
username: string;
|
|
12
|
+
password: string;
|
|
13
|
+
}) => T;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.resolveProvider = resolveProvider;
|
|
4
|
+
/**
|
|
5
|
+
* Looks up a provider class from the registry by name.
|
|
6
|
+
* Throws a clear error if the provider is not registered.
|
|
7
|
+
*
|
|
8
|
+
* Used by both initAuthSession (UI) and initApiAuthSession (API).
|
|
9
|
+
*/
|
|
10
|
+
function resolveProvider(providerName, providerRegistry) {
|
|
11
|
+
const ProviderClass = providerRegistry[providerName];
|
|
12
|
+
if (!ProviderClass) {
|
|
13
|
+
throw new Error(`[Framework] Unknown auth provider: "${providerName}"\n` +
|
|
14
|
+
` Registered providers: ${Object.keys(providerRegistry).join(", ")}`);
|
|
15
|
+
}
|
|
16
|
+
return ProviderClass;
|
|
17
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Page } from "@playwright/test";
|
|
2
|
+
/**
|
|
3
|
+
* Restores a saved auth session into the browser page.
|
|
4
|
+
*
|
|
5
|
+
* Supports two formats:
|
|
6
|
+
*
|
|
7
|
+
* 1. localStorage token format: { token, user }
|
|
8
|
+
* Injects token and user into localStorage via addInitScript
|
|
9
|
+
* so they are available before the page loads.
|
|
10
|
+
*
|
|
11
|
+
* 2. Playwright storageState (cookies/origins):
|
|
12
|
+
* Restores cookies via addCookies — for cookie-based apps.
|
|
13
|
+
*/
|
|
14
|
+
export declare function restoreSession(page: Page, storagePath: string): Promise<void>;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.restoreSession = restoreSession;
|
|
7
|
+
const fs_1 = __importDefault(require("fs"));
|
|
8
|
+
/**
|
|
9
|
+
* Restores a saved auth session into the browser page.
|
|
10
|
+
*
|
|
11
|
+
* Supports two formats:
|
|
12
|
+
*
|
|
13
|
+
* 1. localStorage token format: { token, user }
|
|
14
|
+
* Injects token and user into localStorage via addInitScript
|
|
15
|
+
* so they are available before the page loads.
|
|
16
|
+
*
|
|
17
|
+
* 2. Playwright storageState (cookies/origins):
|
|
18
|
+
* Restores cookies via addCookies — for cookie-based apps.
|
|
19
|
+
*/
|
|
20
|
+
async function restoreSession(page, storagePath) {
|
|
21
|
+
const raw = fs_1.default.readFileSync(storagePath, "utf-8").trim();
|
|
22
|
+
const state = JSON.parse(raw);
|
|
23
|
+
// ── localStorage token format (Nexus and token-based apps) ───
|
|
24
|
+
if (state.token) {
|
|
25
|
+
await page.addInitScript((saved) => {
|
|
26
|
+
localStorage.setItem("token", saved.token);
|
|
27
|
+
if (saved.user)
|
|
28
|
+
localStorage.setItem("user", JSON.stringify(saved.user));
|
|
29
|
+
}, { token: state.token, user: state.user ?? null });
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
// ── Playwright cookie-based storageState ─────────────────────
|
|
33
|
+
if (state.cookies?.length > 0) {
|
|
34
|
+
await page.context().addCookies(state.cookies);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -1 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Builds the file path for storing auth state.
|
|
3
|
+
* Creates the storage directory if it doesn't exist.
|
|
4
|
+
*
|
|
5
|
+
* Format: storage/{provider}-{env}-{username}-auth.json
|
|
6
|
+
*/
|
|
1
7
|
export declare function getStoragePath(provider: string, envName: string, username: string): string;
|
|
@@ -6,6 +6,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.getStoragePath = getStoragePath;
|
|
7
7
|
const fs_1 = __importDefault(require("fs"));
|
|
8
8
|
const path_1 = __importDefault(require("path"));
|
|
9
|
+
/**
|
|
10
|
+
* Builds the file path for storing auth state.
|
|
11
|
+
* Creates the storage directory if it doesn't exist.
|
|
12
|
+
*
|
|
13
|
+
* Format: storage/{provider}-{env}-{username}-auth.json
|
|
14
|
+
*/
|
|
9
15
|
function getStoragePath(provider, envName, username) {
|
|
10
16
|
const storageDir = path_1.default.resolve("storage");
|
|
11
17
|
if (!fs_1.default.existsSync(storageDir))
|
|
@@ -1 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Checks if a stored auth file is valid and not expired.
|
|
3
|
+
*
|
|
4
|
+
* Supports two storage formats:
|
|
5
|
+
*
|
|
6
|
+
* 1. UI / cookie-based (Playwright storageState):
|
|
7
|
+
* { cookies: [...], origins: [...] }
|
|
8
|
+
* Valid if cookies or origins are non-empty and file age < validityMinutes
|
|
9
|
+
*
|
|
10
|
+
* 2. API / token-based:
|
|
11
|
+
* { token: "...", savedAt: 1234567890 }
|
|
12
|
+
* Valid if token exists and (now - savedAt) < validityMinutes
|
|
13
|
+
*/
|
|
1
14
|
export declare function isAuthStoreValid(storagePath: string, validityMinutes: number): boolean;
|
|
@@ -5,6 +5,19 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.isAuthStoreValid = isAuthStoreValid;
|
|
7
7
|
const fs_1 = __importDefault(require("fs"));
|
|
8
|
+
/**
|
|
9
|
+
* Checks if a stored auth file is valid and not expired.
|
|
10
|
+
*
|
|
11
|
+
* Supports two storage formats:
|
|
12
|
+
*
|
|
13
|
+
* 1. UI / cookie-based (Playwright storageState):
|
|
14
|
+
* { cookies: [...], origins: [...] }
|
|
15
|
+
* Valid if cookies or origins are non-empty and file age < validityMinutes
|
|
16
|
+
*
|
|
17
|
+
* 2. API / token-based:
|
|
18
|
+
* { token: "...", savedAt: 1234567890 }
|
|
19
|
+
* Valid if token exists and (now - savedAt) < validityMinutes
|
|
20
|
+
*/
|
|
8
21
|
function isAuthStoreValid(storagePath, validityMinutes) {
|
|
9
22
|
if (!fs_1.default.existsSync(storagePath))
|
|
10
23
|
return false;
|
|
@@ -13,9 +26,19 @@ function isAuthStoreValid(storagePath, validityMinutes) {
|
|
|
13
26
|
return false;
|
|
14
27
|
try {
|
|
15
28
|
const state = JSON.parse(raw);
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
29
|
+
// ── API token format ──────────────────────────────────────
|
|
30
|
+
if (state.token && state.savedAt) {
|
|
31
|
+
const ageMinutes = (Date.now() - state.savedAt) / 60000;
|
|
32
|
+
return ageMinutes < validityMinutes;
|
|
33
|
+
}
|
|
34
|
+
// ── UI / Playwright storageState format ───────────────────
|
|
35
|
+
if (state.cookies !== undefined || state.origins !== undefined) {
|
|
36
|
+
const hasContent = (state.cookies?.length > 0) || (state.origins?.length > 0);
|
|
37
|
+
const stats = fs_1.default.statSync(storagePath);
|
|
38
|
+
const ageMinutes = (Date.now() - stats.mtimeMs) / 60000;
|
|
39
|
+
return hasContent && ageMinutes < validityMinutes;
|
|
40
|
+
}
|
|
41
|
+
return false;
|
|
19
42
|
}
|
|
20
43
|
catch {
|
|
21
44
|
return false;
|
package/package.json
CHANGED