@auth-gate/testing 0.7.1
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/chunk-VFBHRWNY.mjs +67 -0
- package/dist/client-DdLppI95.d.cts +41 -0
- package/dist/client-DdLppI95.d.ts +41 -0
- package/dist/cypress.cjs +172 -0
- package/dist/cypress.d.cts +130 -0
- package/dist/cypress.d.ts +130 -0
- package/dist/cypress.mjs +94 -0
- package/dist/index.cjs +87 -0
- package/dist/index.d.cts +6 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.mjs +10 -0
- package/dist/playwright.cjs +209 -0
- package/dist/playwright.d.cts +59 -0
- package/dist/playwright.d.ts +59 -0
- package/dist/playwright.mjs +119 -0
- package/package.json +53 -0
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
2
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
3
|
+
}) : x)(function(x) {
|
|
4
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
5
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
// src/constants.ts
|
|
9
|
+
var TEST_EMAIL_DOMAIN = "test.authgate.dev";
|
|
10
|
+
var TEST_OTP_CODE = "424242";
|
|
11
|
+
|
|
12
|
+
// src/client.ts
|
|
13
|
+
var AuthGateTest = class {
|
|
14
|
+
constructor(config) {
|
|
15
|
+
if (!config.apiKey) throw new Error("apiKey is required");
|
|
16
|
+
if (!config.baseUrl) throw new Error("baseUrl is required");
|
|
17
|
+
this.apiKey = config.apiKey;
|
|
18
|
+
this.baseUrl = config.baseUrl.replace(/\/$/, "");
|
|
19
|
+
}
|
|
20
|
+
async request(method, path, body) {
|
|
21
|
+
var _a;
|
|
22
|
+
const url = `${this.baseUrl}/api/v1/testing${path}`;
|
|
23
|
+
const res = await fetch(url, {
|
|
24
|
+
method,
|
|
25
|
+
headers: {
|
|
26
|
+
"Content-Type": "application/json",
|
|
27
|
+
Authorization: `Bearer ${this.apiKey}`
|
|
28
|
+
},
|
|
29
|
+
body: body ? JSON.stringify(body) : void 0
|
|
30
|
+
});
|
|
31
|
+
if (!res.ok) {
|
|
32
|
+
const error = await res.json().catch(() => ({ error: res.statusText }));
|
|
33
|
+
throw new Error(
|
|
34
|
+
`AuthGate Testing API error (${res.status}): ${(_a = error.error) != null ? _a : res.statusText}`
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
return res.json();
|
|
38
|
+
}
|
|
39
|
+
async createUser(options) {
|
|
40
|
+
var _a;
|
|
41
|
+
if (!options.email.endsWith(`@${TEST_EMAIL_DOMAIN}`)) {
|
|
42
|
+
throw new Error(`Email must end with @${TEST_EMAIL_DOMAIN}`);
|
|
43
|
+
}
|
|
44
|
+
return this.request("POST", "/users", {
|
|
45
|
+
email: options.email,
|
|
46
|
+
password: options.password,
|
|
47
|
+
name: options.name,
|
|
48
|
+
emailVerified: (_a = options.emailVerified) != null ? _a : true
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
async createSession(userId) {
|
|
52
|
+
return this.request("POST", "/sessions", { userId });
|
|
53
|
+
}
|
|
54
|
+
async deleteUser(userId) {
|
|
55
|
+
return this.request("DELETE", `/users/${userId}`);
|
|
56
|
+
}
|
|
57
|
+
async cleanup() {
|
|
58
|
+
return this.request("DELETE", "/users");
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
export {
|
|
63
|
+
__require,
|
|
64
|
+
TEST_EMAIL_DOMAIN,
|
|
65
|
+
TEST_OTP_CODE,
|
|
66
|
+
AuthGateTest
|
|
67
|
+
};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
interface AuthGateTestConfig {
|
|
2
|
+
apiKey: string;
|
|
3
|
+
baseUrl: string;
|
|
4
|
+
}
|
|
5
|
+
interface CreateTestUserOptions {
|
|
6
|
+
email: string;
|
|
7
|
+
password: string;
|
|
8
|
+
name?: string;
|
|
9
|
+
emailVerified?: boolean;
|
|
10
|
+
}
|
|
11
|
+
interface TestUser {
|
|
12
|
+
id: string;
|
|
13
|
+
email: string;
|
|
14
|
+
name: string | null;
|
|
15
|
+
token: string;
|
|
16
|
+
refreshToken: string;
|
|
17
|
+
expiresAt: string;
|
|
18
|
+
}
|
|
19
|
+
interface TestSession {
|
|
20
|
+
token: string;
|
|
21
|
+
refreshToken: string;
|
|
22
|
+
expiresAt: string;
|
|
23
|
+
}
|
|
24
|
+
interface CleanupResult {
|
|
25
|
+
deleted: number;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
declare class AuthGateTest {
|
|
29
|
+
private apiKey;
|
|
30
|
+
private baseUrl;
|
|
31
|
+
constructor(config: AuthGateTestConfig);
|
|
32
|
+
private request;
|
|
33
|
+
createUser(options: CreateTestUserOptions): Promise<TestUser>;
|
|
34
|
+
createSession(userId: string): Promise<TestSession>;
|
|
35
|
+
deleteUser(userId: string): Promise<{
|
|
36
|
+
deleted: boolean;
|
|
37
|
+
}>;
|
|
38
|
+
cleanup(): Promise<CleanupResult>;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export { type AuthGateTestConfig as A, type CreateTestUserOptions as C, type TestUser as T, type CleanupResult as a, AuthGateTest as b, type TestSession as c };
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
interface AuthGateTestConfig {
|
|
2
|
+
apiKey: string;
|
|
3
|
+
baseUrl: string;
|
|
4
|
+
}
|
|
5
|
+
interface CreateTestUserOptions {
|
|
6
|
+
email: string;
|
|
7
|
+
password: string;
|
|
8
|
+
name?: string;
|
|
9
|
+
emailVerified?: boolean;
|
|
10
|
+
}
|
|
11
|
+
interface TestUser {
|
|
12
|
+
id: string;
|
|
13
|
+
email: string;
|
|
14
|
+
name: string | null;
|
|
15
|
+
token: string;
|
|
16
|
+
refreshToken: string;
|
|
17
|
+
expiresAt: string;
|
|
18
|
+
}
|
|
19
|
+
interface TestSession {
|
|
20
|
+
token: string;
|
|
21
|
+
refreshToken: string;
|
|
22
|
+
expiresAt: string;
|
|
23
|
+
}
|
|
24
|
+
interface CleanupResult {
|
|
25
|
+
deleted: number;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
declare class AuthGateTest {
|
|
29
|
+
private apiKey;
|
|
30
|
+
private baseUrl;
|
|
31
|
+
constructor(config: AuthGateTestConfig);
|
|
32
|
+
private request;
|
|
33
|
+
createUser(options: CreateTestUserOptions): Promise<TestUser>;
|
|
34
|
+
createSession(userId: string): Promise<TestSession>;
|
|
35
|
+
deleteUser(userId: string): Promise<{
|
|
36
|
+
deleted: boolean;
|
|
37
|
+
}>;
|
|
38
|
+
cleanup(): Promise<CleanupResult>;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export { type AuthGateTestConfig as A, type CreateTestUserOptions as C, type TestUser as T, type CleanupResult as a, AuthGateTest as b, type TestSession as c };
|
package/dist/cypress.cjs
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/cypress.ts
|
|
21
|
+
var cypress_exports = {};
|
|
22
|
+
__export(cypress_exports, {
|
|
23
|
+
AuthGateTest: () => AuthGateTest,
|
|
24
|
+
authgateSetup: () => authgateSetup,
|
|
25
|
+
registerAuthGateCommands: () => registerAuthGateCommands
|
|
26
|
+
});
|
|
27
|
+
module.exports = __toCommonJS(cypress_exports);
|
|
28
|
+
var import_core = require("@auth-gate/core");
|
|
29
|
+
|
|
30
|
+
// src/constants.ts
|
|
31
|
+
var TEST_EMAIL_DOMAIN = "test.authgate.dev";
|
|
32
|
+
|
|
33
|
+
// src/client.ts
|
|
34
|
+
var AuthGateTest = class {
|
|
35
|
+
constructor(config) {
|
|
36
|
+
if (!config.apiKey) throw new Error("apiKey is required");
|
|
37
|
+
if (!config.baseUrl) throw new Error("baseUrl is required");
|
|
38
|
+
this.apiKey = config.apiKey;
|
|
39
|
+
this.baseUrl = config.baseUrl.replace(/\/$/, "");
|
|
40
|
+
}
|
|
41
|
+
async request(method, path, body) {
|
|
42
|
+
var _a;
|
|
43
|
+
const url = `${this.baseUrl}/api/v1/testing${path}`;
|
|
44
|
+
const res = await fetch(url, {
|
|
45
|
+
method,
|
|
46
|
+
headers: {
|
|
47
|
+
"Content-Type": "application/json",
|
|
48
|
+
Authorization: `Bearer ${this.apiKey}`
|
|
49
|
+
},
|
|
50
|
+
body: body ? JSON.stringify(body) : void 0
|
|
51
|
+
});
|
|
52
|
+
if (!res.ok) {
|
|
53
|
+
const error = await res.json().catch(() => ({ error: res.statusText }));
|
|
54
|
+
throw new Error(
|
|
55
|
+
`AuthGate Testing API error (${res.status}): ${(_a = error.error) != null ? _a : res.statusText}`
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
return res.json();
|
|
59
|
+
}
|
|
60
|
+
async createUser(options) {
|
|
61
|
+
var _a;
|
|
62
|
+
if (!options.email.endsWith(`@${TEST_EMAIL_DOMAIN}`)) {
|
|
63
|
+
throw new Error(`Email must end with @${TEST_EMAIL_DOMAIN}`);
|
|
64
|
+
}
|
|
65
|
+
return this.request("POST", "/users", {
|
|
66
|
+
email: options.email,
|
|
67
|
+
password: options.password,
|
|
68
|
+
name: options.name,
|
|
69
|
+
emailVerified: (_a = options.emailVerified) != null ? _a : true
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
async createSession(userId) {
|
|
73
|
+
return this.request("POST", "/sessions", { userId });
|
|
74
|
+
}
|
|
75
|
+
async deleteUser(userId) {
|
|
76
|
+
return this.request("DELETE", `/users/${userId}`);
|
|
77
|
+
}
|
|
78
|
+
async cleanup() {
|
|
79
|
+
return this.request("DELETE", "/users");
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
// src/cypress.ts
|
|
84
|
+
function authgateSetup(options) {
|
|
85
|
+
const client = new AuthGateTest({
|
|
86
|
+
apiKey: options.apiKey,
|
|
87
|
+
baseUrl: options.baseUrl
|
|
88
|
+
});
|
|
89
|
+
const coreClient = (0, import_core.createAuthGateClient)({
|
|
90
|
+
apiKey: options.apiKey,
|
|
91
|
+
baseUrl: options.baseUrl
|
|
92
|
+
});
|
|
93
|
+
options.config.env = options.config.env || {};
|
|
94
|
+
options.config.env.AUTHGATE_COOKIE_NAME = coreClient.cookieName;
|
|
95
|
+
options.config.env.AUTHGATE_REFRESH_COOKIE_NAME = coreClient.refreshTokenCookieName;
|
|
96
|
+
options.on("task", {
|
|
97
|
+
"authgate:createUser": async (opts) => {
|
|
98
|
+
return client.createUser(opts);
|
|
99
|
+
},
|
|
100
|
+
"authgate:createSession": async (userId) => {
|
|
101
|
+
return client.createSession(userId);
|
|
102
|
+
},
|
|
103
|
+
"authgate:cleanup": async () => {
|
|
104
|
+
return client.cleanup();
|
|
105
|
+
},
|
|
106
|
+
"authgate:deleteUser": async (userId) => {
|
|
107
|
+
return client.deleteUser(userId);
|
|
108
|
+
},
|
|
109
|
+
"authgate:encryptSession": async (user) => {
|
|
110
|
+
return coreClient.encryptSession({
|
|
111
|
+
id: user.id,
|
|
112
|
+
email: user.email,
|
|
113
|
+
phone: null,
|
|
114
|
+
name: user.name,
|
|
115
|
+
picture: null,
|
|
116
|
+
provider: "email"
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
if (options.cleanupOnStart) {
|
|
121
|
+
options.on("before:run", async () => {
|
|
122
|
+
await client.cleanup();
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
return options.config;
|
|
126
|
+
}
|
|
127
|
+
function registerAuthGateCommands() {
|
|
128
|
+
Cypress.Commands.add("authgateCreateUser", (options) => {
|
|
129
|
+
return cy.task("authgate:createUser", options);
|
|
130
|
+
});
|
|
131
|
+
Cypress.Commands.add("authgateSignIn", (options) => {
|
|
132
|
+
return cy.task("authgate:createUser", options).then((user) => {
|
|
133
|
+
return cy.task("authgate:encryptSession", {
|
|
134
|
+
id: user.id,
|
|
135
|
+
email: user.email,
|
|
136
|
+
name: user.name
|
|
137
|
+
}).then((encryptedSession) => {
|
|
138
|
+
const cookieName = Cypress.env(
|
|
139
|
+
"AUTHGATE_COOKIE_NAME"
|
|
140
|
+
);
|
|
141
|
+
const refreshCookieName = Cypress.env(
|
|
142
|
+
"AUTHGATE_REFRESH_COOKIE_NAME"
|
|
143
|
+
);
|
|
144
|
+
cy.setCookie(cookieName, encryptedSession, {
|
|
145
|
+
httpOnly: true,
|
|
146
|
+
secure: false,
|
|
147
|
+
sameSite: "lax",
|
|
148
|
+
path: "/"
|
|
149
|
+
});
|
|
150
|
+
cy.setCookie(refreshCookieName, user.refreshToken, {
|
|
151
|
+
httpOnly: true,
|
|
152
|
+
secure: false,
|
|
153
|
+
sameSite: "lax",
|
|
154
|
+
path: "/"
|
|
155
|
+
});
|
|
156
|
+
return cy.wrap(user);
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
});
|
|
160
|
+
Cypress.Commands.add("authgateCleanup", () => {
|
|
161
|
+
return cy.task("authgate:cleanup");
|
|
162
|
+
});
|
|
163
|
+
Cypress.Commands.add("authgateDeleteUser", (userId) => {
|
|
164
|
+
return cy.task("authgate:deleteUser", userId);
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
168
|
+
0 && (module.exports = {
|
|
169
|
+
AuthGateTest,
|
|
170
|
+
authgateSetup,
|
|
171
|
+
registerAuthGateCommands
|
|
172
|
+
});
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { C as CreateTestUserOptions, T as TestUser, a as CleanupResult, A as AuthGateTestConfig } from './client-DdLppI95.cjs';
|
|
2
|
+
export { b as AuthGateTest, c as TestSession } from './client-DdLppI95.cjs';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Options for setting up the AuthGate Cypress plugin.
|
|
6
|
+
*
|
|
7
|
+
* Pass these in your `cypress.config.ts` `setupNodeEvents` callback:
|
|
8
|
+
*
|
|
9
|
+
* ```ts
|
|
10
|
+
* import { authgateSetup } from "@auth-gate/testing/cypress";
|
|
11
|
+
*
|
|
12
|
+
* export default defineConfig({
|
|
13
|
+
* e2e: {
|
|
14
|
+
* setupNodeEvents(on, config) {
|
|
15
|
+
* return authgateSetup({
|
|
16
|
+
* on,
|
|
17
|
+
* config,
|
|
18
|
+
* apiKey: process.env.AUTHGATE_API_KEY!,
|
|
19
|
+
* baseUrl: process.env.AUTHGATE_BASE_URL!,
|
|
20
|
+
* cleanupOnStart: true,
|
|
21
|
+
* });
|
|
22
|
+
* },
|
|
23
|
+
* },
|
|
24
|
+
* });
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
interface CypressSetupOptions extends AuthGateTestConfig {
|
|
28
|
+
/** The `on` callback provided by Cypress `setupNodeEvents`. */
|
|
29
|
+
on: Cypress.PluginEvents;
|
|
30
|
+
/** The `config` object provided by Cypress `setupNodeEvents`. */
|
|
31
|
+
config: Cypress.PluginConfigOptions;
|
|
32
|
+
/** If `true`, delete all test users before the Cypress run starts. */
|
|
33
|
+
cleanupOnStart?: boolean;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Register AuthGate Cypress tasks and environment variables.
|
|
37
|
+
*
|
|
38
|
+
* Call this inside `setupNodeEvents` in your `cypress.config.ts`. It:
|
|
39
|
+
*
|
|
40
|
+
* 1. Creates an {@link AuthGateTest} client (for the Testing API) and an
|
|
41
|
+
* {@link AuthGateClient} (for session encryption).
|
|
42
|
+
* 2. Stores cookie names in `config.env` so browser-side commands can read them.
|
|
43
|
+
* 3. Registers Cypress tasks: `authgate:createUser`, `authgate:createSession`,
|
|
44
|
+
* `authgate:cleanup`, `authgate:deleteUser`, `authgate:encryptSession`.
|
|
45
|
+
* 4. Optionally registers a `before:run` hook to clean up leftover test users.
|
|
46
|
+
*
|
|
47
|
+
* @param options - API key, base URL, Cypress `on`/`config`, and flags.
|
|
48
|
+
* @returns The mutated `config` object (return this from `setupNodeEvents`).
|
|
49
|
+
*/
|
|
50
|
+
declare function authgateSetup(options: CypressSetupOptions): Cypress.PluginConfigOptions;
|
|
51
|
+
/**
|
|
52
|
+
* Register AuthGate custom commands on the global `Cypress` object.
|
|
53
|
+
*
|
|
54
|
+
* Call this once in your `cypress/support/e2e.ts` (or `commands.ts`):
|
|
55
|
+
*
|
|
56
|
+
* ```ts
|
|
57
|
+
* import { registerAuthGateCommands } from "@auth-gate/testing/cypress";
|
|
58
|
+
* registerAuthGateCommands();
|
|
59
|
+
* ```
|
|
60
|
+
*
|
|
61
|
+
* This adds:
|
|
62
|
+
* - `cy.authgateCreateUser(options)` — create a test user via the Testing API.
|
|
63
|
+
* - `cy.authgateSignIn(options)` — create a user, encrypt a session, and set
|
|
64
|
+
* the session + refresh-token cookies so the browser is fully authenticated.
|
|
65
|
+
* - `cy.authgateCleanup()` — bulk-delete all test users created during the run.
|
|
66
|
+
* - `cy.authgateDeleteUser(userId)` — delete a specific test user.
|
|
67
|
+
*/
|
|
68
|
+
declare function registerAuthGateCommands(): void;
|
|
69
|
+
declare global {
|
|
70
|
+
namespace Cypress {
|
|
71
|
+
interface Chainable {
|
|
72
|
+
/**
|
|
73
|
+
* Create a test user via the AuthGate Testing API.
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* ```ts
|
|
77
|
+
* cy.authgateCreateUser({
|
|
78
|
+
* email: "alice@test.authgate.dev",
|
|
79
|
+
* password: "password123",
|
|
80
|
+
* }).then((user) => {
|
|
81
|
+
* expect(user.id).to.be.a("string");
|
|
82
|
+
* });
|
|
83
|
+
* ```
|
|
84
|
+
*/
|
|
85
|
+
authgateCreateUser(options: CreateTestUserOptions): Chainable<TestUser>;
|
|
86
|
+
/**
|
|
87
|
+
* Create a test user and inject an authenticated session.
|
|
88
|
+
*
|
|
89
|
+
* This creates the user, encrypts a session cookie, and sets both the
|
|
90
|
+
* session and refresh-token cookies on the current domain so subsequent
|
|
91
|
+
* page visits are fully authenticated.
|
|
92
|
+
*
|
|
93
|
+
* @example
|
|
94
|
+
* ```ts
|
|
95
|
+
* cy.authgateSignIn({
|
|
96
|
+
* email: "alice@test.authgate.dev",
|
|
97
|
+
* password: "password123",
|
|
98
|
+
* }).then((user) => {
|
|
99
|
+
* cy.visit("/dashboard");
|
|
100
|
+
* });
|
|
101
|
+
* ```
|
|
102
|
+
*/
|
|
103
|
+
authgateSignIn(options: CreateTestUserOptions): Chainable<TestUser>;
|
|
104
|
+
/**
|
|
105
|
+
* Bulk-delete all test users created during this run.
|
|
106
|
+
*
|
|
107
|
+
* @example
|
|
108
|
+
* ```ts
|
|
109
|
+
* afterEach(() => {
|
|
110
|
+
* cy.authgateCleanup();
|
|
111
|
+
* });
|
|
112
|
+
* ```
|
|
113
|
+
*/
|
|
114
|
+
authgateCleanup(): Chainable<CleanupResult>;
|
|
115
|
+
/**
|
|
116
|
+
* Delete a specific test user by ID.
|
|
117
|
+
*
|
|
118
|
+
* @example
|
|
119
|
+
* ```ts
|
|
120
|
+
* cy.authgateDeleteUser(user.id);
|
|
121
|
+
* ```
|
|
122
|
+
*/
|
|
123
|
+
authgateDeleteUser(userId: string): Chainable<{
|
|
124
|
+
deleted: boolean;
|
|
125
|
+
}>;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export { CreateTestUserOptions, type CypressSetupOptions, TestUser, authgateSetup, registerAuthGateCommands };
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { C as CreateTestUserOptions, T as TestUser, a as CleanupResult, A as AuthGateTestConfig } from './client-DdLppI95.js';
|
|
2
|
+
export { b as AuthGateTest, c as TestSession } from './client-DdLppI95.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Options for setting up the AuthGate Cypress plugin.
|
|
6
|
+
*
|
|
7
|
+
* Pass these in your `cypress.config.ts` `setupNodeEvents` callback:
|
|
8
|
+
*
|
|
9
|
+
* ```ts
|
|
10
|
+
* import { authgateSetup } from "@auth-gate/testing/cypress";
|
|
11
|
+
*
|
|
12
|
+
* export default defineConfig({
|
|
13
|
+
* e2e: {
|
|
14
|
+
* setupNodeEvents(on, config) {
|
|
15
|
+
* return authgateSetup({
|
|
16
|
+
* on,
|
|
17
|
+
* config,
|
|
18
|
+
* apiKey: process.env.AUTHGATE_API_KEY!,
|
|
19
|
+
* baseUrl: process.env.AUTHGATE_BASE_URL!,
|
|
20
|
+
* cleanupOnStart: true,
|
|
21
|
+
* });
|
|
22
|
+
* },
|
|
23
|
+
* },
|
|
24
|
+
* });
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
interface CypressSetupOptions extends AuthGateTestConfig {
|
|
28
|
+
/** The `on` callback provided by Cypress `setupNodeEvents`. */
|
|
29
|
+
on: Cypress.PluginEvents;
|
|
30
|
+
/** The `config` object provided by Cypress `setupNodeEvents`. */
|
|
31
|
+
config: Cypress.PluginConfigOptions;
|
|
32
|
+
/** If `true`, delete all test users before the Cypress run starts. */
|
|
33
|
+
cleanupOnStart?: boolean;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Register AuthGate Cypress tasks and environment variables.
|
|
37
|
+
*
|
|
38
|
+
* Call this inside `setupNodeEvents` in your `cypress.config.ts`. It:
|
|
39
|
+
*
|
|
40
|
+
* 1. Creates an {@link AuthGateTest} client (for the Testing API) and an
|
|
41
|
+
* {@link AuthGateClient} (for session encryption).
|
|
42
|
+
* 2. Stores cookie names in `config.env` so browser-side commands can read them.
|
|
43
|
+
* 3. Registers Cypress tasks: `authgate:createUser`, `authgate:createSession`,
|
|
44
|
+
* `authgate:cleanup`, `authgate:deleteUser`, `authgate:encryptSession`.
|
|
45
|
+
* 4. Optionally registers a `before:run` hook to clean up leftover test users.
|
|
46
|
+
*
|
|
47
|
+
* @param options - API key, base URL, Cypress `on`/`config`, and flags.
|
|
48
|
+
* @returns The mutated `config` object (return this from `setupNodeEvents`).
|
|
49
|
+
*/
|
|
50
|
+
declare function authgateSetup(options: CypressSetupOptions): Cypress.PluginConfigOptions;
|
|
51
|
+
/**
|
|
52
|
+
* Register AuthGate custom commands on the global `Cypress` object.
|
|
53
|
+
*
|
|
54
|
+
* Call this once in your `cypress/support/e2e.ts` (or `commands.ts`):
|
|
55
|
+
*
|
|
56
|
+
* ```ts
|
|
57
|
+
* import { registerAuthGateCommands } from "@auth-gate/testing/cypress";
|
|
58
|
+
* registerAuthGateCommands();
|
|
59
|
+
* ```
|
|
60
|
+
*
|
|
61
|
+
* This adds:
|
|
62
|
+
* - `cy.authgateCreateUser(options)` — create a test user via the Testing API.
|
|
63
|
+
* - `cy.authgateSignIn(options)` — create a user, encrypt a session, and set
|
|
64
|
+
* the session + refresh-token cookies so the browser is fully authenticated.
|
|
65
|
+
* - `cy.authgateCleanup()` — bulk-delete all test users created during the run.
|
|
66
|
+
* - `cy.authgateDeleteUser(userId)` — delete a specific test user.
|
|
67
|
+
*/
|
|
68
|
+
declare function registerAuthGateCommands(): void;
|
|
69
|
+
declare global {
|
|
70
|
+
namespace Cypress {
|
|
71
|
+
interface Chainable {
|
|
72
|
+
/**
|
|
73
|
+
* Create a test user via the AuthGate Testing API.
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* ```ts
|
|
77
|
+
* cy.authgateCreateUser({
|
|
78
|
+
* email: "alice@test.authgate.dev",
|
|
79
|
+
* password: "password123",
|
|
80
|
+
* }).then((user) => {
|
|
81
|
+
* expect(user.id).to.be.a("string");
|
|
82
|
+
* });
|
|
83
|
+
* ```
|
|
84
|
+
*/
|
|
85
|
+
authgateCreateUser(options: CreateTestUserOptions): Chainable<TestUser>;
|
|
86
|
+
/**
|
|
87
|
+
* Create a test user and inject an authenticated session.
|
|
88
|
+
*
|
|
89
|
+
* This creates the user, encrypts a session cookie, and sets both the
|
|
90
|
+
* session and refresh-token cookies on the current domain so subsequent
|
|
91
|
+
* page visits are fully authenticated.
|
|
92
|
+
*
|
|
93
|
+
* @example
|
|
94
|
+
* ```ts
|
|
95
|
+
* cy.authgateSignIn({
|
|
96
|
+
* email: "alice@test.authgate.dev",
|
|
97
|
+
* password: "password123",
|
|
98
|
+
* }).then((user) => {
|
|
99
|
+
* cy.visit("/dashboard");
|
|
100
|
+
* });
|
|
101
|
+
* ```
|
|
102
|
+
*/
|
|
103
|
+
authgateSignIn(options: CreateTestUserOptions): Chainable<TestUser>;
|
|
104
|
+
/**
|
|
105
|
+
* Bulk-delete all test users created during this run.
|
|
106
|
+
*
|
|
107
|
+
* @example
|
|
108
|
+
* ```ts
|
|
109
|
+
* afterEach(() => {
|
|
110
|
+
* cy.authgateCleanup();
|
|
111
|
+
* });
|
|
112
|
+
* ```
|
|
113
|
+
*/
|
|
114
|
+
authgateCleanup(): Chainable<CleanupResult>;
|
|
115
|
+
/**
|
|
116
|
+
* Delete a specific test user by ID.
|
|
117
|
+
*
|
|
118
|
+
* @example
|
|
119
|
+
* ```ts
|
|
120
|
+
* cy.authgateDeleteUser(user.id);
|
|
121
|
+
* ```
|
|
122
|
+
*/
|
|
123
|
+
authgateDeleteUser(userId: string): Chainable<{
|
|
124
|
+
deleted: boolean;
|
|
125
|
+
}>;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export { CreateTestUserOptions, type CypressSetupOptions, TestUser, authgateSetup, registerAuthGateCommands };
|
package/dist/cypress.mjs
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AuthGateTest
|
|
3
|
+
} from "./chunk-VFBHRWNY.mjs";
|
|
4
|
+
|
|
5
|
+
// src/cypress.ts
|
|
6
|
+
import { createAuthGateClient } from "@auth-gate/core";
|
|
7
|
+
function authgateSetup(options) {
|
|
8
|
+
const client = new AuthGateTest({
|
|
9
|
+
apiKey: options.apiKey,
|
|
10
|
+
baseUrl: options.baseUrl
|
|
11
|
+
});
|
|
12
|
+
const coreClient = createAuthGateClient({
|
|
13
|
+
apiKey: options.apiKey,
|
|
14
|
+
baseUrl: options.baseUrl
|
|
15
|
+
});
|
|
16
|
+
options.config.env = options.config.env || {};
|
|
17
|
+
options.config.env.AUTHGATE_COOKIE_NAME = coreClient.cookieName;
|
|
18
|
+
options.config.env.AUTHGATE_REFRESH_COOKIE_NAME = coreClient.refreshTokenCookieName;
|
|
19
|
+
options.on("task", {
|
|
20
|
+
"authgate:createUser": async (opts) => {
|
|
21
|
+
return client.createUser(opts);
|
|
22
|
+
},
|
|
23
|
+
"authgate:createSession": async (userId) => {
|
|
24
|
+
return client.createSession(userId);
|
|
25
|
+
},
|
|
26
|
+
"authgate:cleanup": async () => {
|
|
27
|
+
return client.cleanup();
|
|
28
|
+
},
|
|
29
|
+
"authgate:deleteUser": async (userId) => {
|
|
30
|
+
return client.deleteUser(userId);
|
|
31
|
+
},
|
|
32
|
+
"authgate:encryptSession": async (user) => {
|
|
33
|
+
return coreClient.encryptSession({
|
|
34
|
+
id: user.id,
|
|
35
|
+
email: user.email,
|
|
36
|
+
phone: null,
|
|
37
|
+
name: user.name,
|
|
38
|
+
picture: null,
|
|
39
|
+
provider: "email"
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
if (options.cleanupOnStart) {
|
|
44
|
+
options.on("before:run", async () => {
|
|
45
|
+
await client.cleanup();
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
return options.config;
|
|
49
|
+
}
|
|
50
|
+
function registerAuthGateCommands() {
|
|
51
|
+
Cypress.Commands.add("authgateCreateUser", (options) => {
|
|
52
|
+
return cy.task("authgate:createUser", options);
|
|
53
|
+
});
|
|
54
|
+
Cypress.Commands.add("authgateSignIn", (options) => {
|
|
55
|
+
return cy.task("authgate:createUser", options).then((user) => {
|
|
56
|
+
return cy.task("authgate:encryptSession", {
|
|
57
|
+
id: user.id,
|
|
58
|
+
email: user.email,
|
|
59
|
+
name: user.name
|
|
60
|
+
}).then((encryptedSession) => {
|
|
61
|
+
const cookieName = Cypress.env(
|
|
62
|
+
"AUTHGATE_COOKIE_NAME"
|
|
63
|
+
);
|
|
64
|
+
const refreshCookieName = Cypress.env(
|
|
65
|
+
"AUTHGATE_REFRESH_COOKIE_NAME"
|
|
66
|
+
);
|
|
67
|
+
cy.setCookie(cookieName, encryptedSession, {
|
|
68
|
+
httpOnly: true,
|
|
69
|
+
secure: false,
|
|
70
|
+
sameSite: "lax",
|
|
71
|
+
path: "/"
|
|
72
|
+
});
|
|
73
|
+
cy.setCookie(refreshCookieName, user.refreshToken, {
|
|
74
|
+
httpOnly: true,
|
|
75
|
+
secure: false,
|
|
76
|
+
sameSite: "lax",
|
|
77
|
+
path: "/"
|
|
78
|
+
});
|
|
79
|
+
return cy.wrap(user);
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
Cypress.Commands.add("authgateCleanup", () => {
|
|
84
|
+
return cy.task("authgate:cleanup");
|
|
85
|
+
});
|
|
86
|
+
Cypress.Commands.add("authgateDeleteUser", (userId) => {
|
|
87
|
+
return cy.task("authgate:deleteUser", userId);
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
export {
|
|
91
|
+
AuthGateTest,
|
|
92
|
+
authgateSetup,
|
|
93
|
+
registerAuthGateCommands
|
|
94
|
+
};
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
AuthGateTest: () => AuthGateTest,
|
|
24
|
+
TEST_EMAIL_DOMAIN: () => TEST_EMAIL_DOMAIN,
|
|
25
|
+
TEST_OTP_CODE: () => TEST_OTP_CODE
|
|
26
|
+
});
|
|
27
|
+
module.exports = __toCommonJS(index_exports);
|
|
28
|
+
|
|
29
|
+
// src/constants.ts
|
|
30
|
+
var TEST_EMAIL_DOMAIN = "test.authgate.dev";
|
|
31
|
+
var TEST_OTP_CODE = "424242";
|
|
32
|
+
|
|
33
|
+
// src/client.ts
|
|
34
|
+
var AuthGateTest = class {
|
|
35
|
+
constructor(config) {
|
|
36
|
+
if (!config.apiKey) throw new Error("apiKey is required");
|
|
37
|
+
if (!config.baseUrl) throw new Error("baseUrl is required");
|
|
38
|
+
this.apiKey = config.apiKey;
|
|
39
|
+
this.baseUrl = config.baseUrl.replace(/\/$/, "");
|
|
40
|
+
}
|
|
41
|
+
async request(method, path, body) {
|
|
42
|
+
var _a;
|
|
43
|
+
const url = `${this.baseUrl}/api/v1/testing${path}`;
|
|
44
|
+
const res = await fetch(url, {
|
|
45
|
+
method,
|
|
46
|
+
headers: {
|
|
47
|
+
"Content-Type": "application/json",
|
|
48
|
+
Authorization: `Bearer ${this.apiKey}`
|
|
49
|
+
},
|
|
50
|
+
body: body ? JSON.stringify(body) : void 0
|
|
51
|
+
});
|
|
52
|
+
if (!res.ok) {
|
|
53
|
+
const error = await res.json().catch(() => ({ error: res.statusText }));
|
|
54
|
+
throw new Error(
|
|
55
|
+
`AuthGate Testing API error (${res.status}): ${(_a = error.error) != null ? _a : res.statusText}`
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
return res.json();
|
|
59
|
+
}
|
|
60
|
+
async createUser(options) {
|
|
61
|
+
var _a;
|
|
62
|
+
if (!options.email.endsWith(`@${TEST_EMAIL_DOMAIN}`)) {
|
|
63
|
+
throw new Error(`Email must end with @${TEST_EMAIL_DOMAIN}`);
|
|
64
|
+
}
|
|
65
|
+
return this.request("POST", "/users", {
|
|
66
|
+
email: options.email,
|
|
67
|
+
password: options.password,
|
|
68
|
+
name: options.name,
|
|
69
|
+
emailVerified: (_a = options.emailVerified) != null ? _a : true
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
async createSession(userId) {
|
|
73
|
+
return this.request("POST", "/sessions", { userId });
|
|
74
|
+
}
|
|
75
|
+
async deleteUser(userId) {
|
|
76
|
+
return this.request("DELETE", `/users/${userId}`);
|
|
77
|
+
}
|
|
78
|
+
async cleanup() {
|
|
79
|
+
return this.request("DELETE", "/users");
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
83
|
+
0 && (module.exports = {
|
|
84
|
+
AuthGateTest,
|
|
85
|
+
TEST_EMAIL_DOMAIN,
|
|
86
|
+
TEST_OTP_CODE
|
|
87
|
+
});
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { b as AuthGateTest, A as AuthGateTestConfig, a as CleanupResult, C as CreateTestUserOptions, c as TestSession, T as TestUser } from './client-DdLppI95.cjs';
|
|
2
|
+
|
|
3
|
+
declare const TEST_EMAIL_DOMAIN = "test.authgate.dev";
|
|
4
|
+
declare const TEST_OTP_CODE = "424242";
|
|
5
|
+
|
|
6
|
+
export { TEST_EMAIL_DOMAIN, TEST_OTP_CODE };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { b as AuthGateTest, A as AuthGateTestConfig, a as CleanupResult, C as CreateTestUserOptions, c as TestSession, T as TestUser } from './client-DdLppI95.js';
|
|
2
|
+
|
|
3
|
+
declare const TEST_EMAIL_DOMAIN = "test.authgate.dev";
|
|
4
|
+
declare const TEST_OTP_CODE = "424242";
|
|
5
|
+
|
|
6
|
+
export { TEST_EMAIL_DOMAIN, TEST_OTP_CODE };
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/playwright.ts
|
|
31
|
+
var playwright_exports = {};
|
|
32
|
+
__export(playwright_exports, {
|
|
33
|
+
AuthGateTest: () => AuthGateTest,
|
|
34
|
+
authgateSetup: () => authgateSetup,
|
|
35
|
+
authgateTeardown: () => authgateTeardown,
|
|
36
|
+
cleanup: () => cleanup,
|
|
37
|
+
createTestUser: () => createTestUser,
|
|
38
|
+
injectSession: () => injectSession
|
|
39
|
+
});
|
|
40
|
+
module.exports = __toCommonJS(playwright_exports);
|
|
41
|
+
var import_core = require("@auth-gate/core");
|
|
42
|
+
|
|
43
|
+
// src/constants.ts
|
|
44
|
+
var TEST_EMAIL_DOMAIN = "test.authgate.dev";
|
|
45
|
+
|
|
46
|
+
// src/client.ts
|
|
47
|
+
var AuthGateTest = class {
|
|
48
|
+
constructor(config) {
|
|
49
|
+
if (!config.apiKey) throw new Error("apiKey is required");
|
|
50
|
+
if (!config.baseUrl) throw new Error("baseUrl is required");
|
|
51
|
+
this.apiKey = config.apiKey;
|
|
52
|
+
this.baseUrl = config.baseUrl.replace(/\/$/, "");
|
|
53
|
+
}
|
|
54
|
+
async request(method, path, body) {
|
|
55
|
+
var _a;
|
|
56
|
+
const url = `${this.baseUrl}/api/v1/testing${path}`;
|
|
57
|
+
const res = await fetch(url, {
|
|
58
|
+
method,
|
|
59
|
+
headers: {
|
|
60
|
+
"Content-Type": "application/json",
|
|
61
|
+
Authorization: `Bearer ${this.apiKey}`
|
|
62
|
+
},
|
|
63
|
+
body: body ? JSON.stringify(body) : void 0
|
|
64
|
+
});
|
|
65
|
+
if (!res.ok) {
|
|
66
|
+
const error = await res.json().catch(() => ({ error: res.statusText }));
|
|
67
|
+
throw new Error(
|
|
68
|
+
`AuthGate Testing API error (${res.status}): ${(_a = error.error) != null ? _a : res.statusText}`
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
return res.json();
|
|
72
|
+
}
|
|
73
|
+
async createUser(options) {
|
|
74
|
+
var _a;
|
|
75
|
+
if (!options.email.endsWith(`@${TEST_EMAIL_DOMAIN}`)) {
|
|
76
|
+
throw new Error(`Email must end with @${TEST_EMAIL_DOMAIN}`);
|
|
77
|
+
}
|
|
78
|
+
return this.request("POST", "/users", {
|
|
79
|
+
email: options.email,
|
|
80
|
+
password: options.password,
|
|
81
|
+
name: options.name,
|
|
82
|
+
emailVerified: (_a = options.emailVerified) != null ? _a : true
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
async createSession(userId) {
|
|
86
|
+
return this.request("POST", "/sessions", { userId });
|
|
87
|
+
}
|
|
88
|
+
async deleteUser(userId) {
|
|
89
|
+
return this.request("DELETE", `/users/${userId}`);
|
|
90
|
+
}
|
|
91
|
+
async cleanup() {
|
|
92
|
+
return this.request("DELETE", "/users");
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
// src/playwright.ts
|
|
97
|
+
var STATE_FILE = ".authgate-test-state.json";
|
|
98
|
+
var _client = null;
|
|
99
|
+
var _coreClient = null;
|
|
100
|
+
var _config = null;
|
|
101
|
+
function getClient() {
|
|
102
|
+
if (!_client) {
|
|
103
|
+
throw new Error(
|
|
104
|
+
"AuthGate testing not initialized. Call authgateSetup() in your global setup first."
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
return _client;
|
|
108
|
+
}
|
|
109
|
+
function getCoreClient() {
|
|
110
|
+
if (!_coreClient) {
|
|
111
|
+
throw new Error(
|
|
112
|
+
"AuthGate testing not initialized. Call authgateSetup() in your global setup first."
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
return _coreClient;
|
|
116
|
+
}
|
|
117
|
+
async function authgateSetup(options) {
|
|
118
|
+
_config = { apiKey: options.apiKey, baseUrl: options.baseUrl };
|
|
119
|
+
_client = new AuthGateTest(_config);
|
|
120
|
+
_coreClient = (0, import_core.createAuthGateClient)({
|
|
121
|
+
apiKey: options.apiKey,
|
|
122
|
+
baseUrl: options.baseUrl
|
|
123
|
+
});
|
|
124
|
+
if (options.cleanupOnStart) {
|
|
125
|
+
await _client.cleanup();
|
|
126
|
+
}
|
|
127
|
+
const fs = await import("fs");
|
|
128
|
+
fs.writeFileSync(STATE_FILE, JSON.stringify(_config), "utf-8");
|
|
129
|
+
}
|
|
130
|
+
async function authgateTeardown() {
|
|
131
|
+
if (_client) {
|
|
132
|
+
await _client.cleanup();
|
|
133
|
+
}
|
|
134
|
+
const fs = await import("fs");
|
|
135
|
+
if (fs.existsSync(STATE_FILE)) {
|
|
136
|
+
fs.unlinkSync(STATE_FILE);
|
|
137
|
+
}
|
|
138
|
+
_client = null;
|
|
139
|
+
_coreClient = null;
|
|
140
|
+
_config = null;
|
|
141
|
+
}
|
|
142
|
+
function ensureInitialized() {
|
|
143
|
+
if (_client) return;
|
|
144
|
+
const fs = require("fs");
|
|
145
|
+
if (fs.existsSync(STATE_FILE)) {
|
|
146
|
+
const config = JSON.parse(
|
|
147
|
+
fs.readFileSync(STATE_FILE, "utf-8")
|
|
148
|
+
);
|
|
149
|
+
_config = config;
|
|
150
|
+
_client = new AuthGateTest(config);
|
|
151
|
+
_coreClient = (0, import_core.createAuthGateClient)({
|
|
152
|
+
apiKey: config.apiKey,
|
|
153
|
+
baseUrl: config.baseUrl
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
async function createTestUser(options) {
|
|
158
|
+
ensureInitialized();
|
|
159
|
+
return getClient().createUser(options);
|
|
160
|
+
}
|
|
161
|
+
async function injectSession({
|
|
162
|
+
context,
|
|
163
|
+
user,
|
|
164
|
+
domain = "localhost"
|
|
165
|
+
}) {
|
|
166
|
+
ensureInitialized();
|
|
167
|
+
const client = getCoreClient();
|
|
168
|
+
const encryptedSession = await client.encryptSession({
|
|
169
|
+
id: user.id,
|
|
170
|
+
email: user.email,
|
|
171
|
+
phone: null,
|
|
172
|
+
name: user.name,
|
|
173
|
+
picture: null,
|
|
174
|
+
provider: "email"
|
|
175
|
+
});
|
|
176
|
+
await context.addCookies([
|
|
177
|
+
{
|
|
178
|
+
name: client.cookieName,
|
|
179
|
+
value: encryptedSession,
|
|
180
|
+
domain,
|
|
181
|
+
path: "/",
|
|
182
|
+
httpOnly: true,
|
|
183
|
+
secure: false,
|
|
184
|
+
sameSite: "Lax"
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
name: client.refreshTokenCookieName,
|
|
188
|
+
value: user.refreshToken,
|
|
189
|
+
domain,
|
|
190
|
+
path: "/",
|
|
191
|
+
httpOnly: true,
|
|
192
|
+
secure: false,
|
|
193
|
+
sameSite: "Lax"
|
|
194
|
+
}
|
|
195
|
+
]);
|
|
196
|
+
}
|
|
197
|
+
async function cleanup() {
|
|
198
|
+
ensureInitialized();
|
|
199
|
+
return getClient().cleanup();
|
|
200
|
+
}
|
|
201
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
202
|
+
0 && (module.exports = {
|
|
203
|
+
AuthGateTest,
|
|
204
|
+
authgateSetup,
|
|
205
|
+
authgateTeardown,
|
|
206
|
+
cleanup,
|
|
207
|
+
createTestUser,
|
|
208
|
+
injectSession
|
|
209
|
+
});
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { A as AuthGateTestConfig, C as CreateTestUserOptions, T as TestUser } from './client-DdLppI95.cjs';
|
|
2
|
+
export { b as AuthGateTest, c as TestSession } from './client-DdLppI95.cjs';
|
|
3
|
+
|
|
4
|
+
interface AuthGateSetupOptions extends AuthGateTestConfig {
|
|
5
|
+
cleanupOnStart?: boolean;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Initialise the AuthGate testing helpers.
|
|
9
|
+
*
|
|
10
|
+
* Call this once in your Playwright **global setup** file.
|
|
11
|
+
* It persists the config to a temporary JSON file so that worker processes
|
|
12
|
+
* spawned by Playwright can pick it up via {@link ensureInitialized}.
|
|
13
|
+
*
|
|
14
|
+
* @param options - API key, base URL, and optional `cleanupOnStart` flag.
|
|
15
|
+
*/
|
|
16
|
+
declare function authgateSetup(options: AuthGateSetupOptions): Promise<void>;
|
|
17
|
+
/**
|
|
18
|
+
* Tear down the AuthGate testing helpers.
|
|
19
|
+
*
|
|
20
|
+
* Call this in your Playwright **global teardown** file.
|
|
21
|
+
* It deletes all test users created during the run and removes the
|
|
22
|
+
* temporary state file.
|
|
23
|
+
*/
|
|
24
|
+
declare function authgateTeardown(): Promise<void>;
|
|
25
|
+
/**
|
|
26
|
+
* Create a test user via the AuthGate Testing API.
|
|
27
|
+
*
|
|
28
|
+
* Returns a {@link TestUser} with valid `token` and `refreshToken` that can
|
|
29
|
+
* be passed to {@link injectSession}.
|
|
30
|
+
*/
|
|
31
|
+
declare function createTestUser(options: CreateTestUserOptions): Promise<TestUser>;
|
|
32
|
+
/**
|
|
33
|
+
* Inject an authenticated session into a Playwright {@link BrowserContext}.
|
|
34
|
+
*
|
|
35
|
+
* Sets the encrypted session cookie and refresh-token cookie so that the
|
|
36
|
+
* browser context appears fully logged-in without going through the UI
|
|
37
|
+
* sign-in flow.
|
|
38
|
+
*
|
|
39
|
+
* @param params.context - A Playwright `BrowserContext` (or anything with `addCookies`).
|
|
40
|
+
* @param params.user - The {@link TestUser} returned by {@link createTestUser}.
|
|
41
|
+
* @param params.domain - Cookie domain (defaults to `"localhost"`).
|
|
42
|
+
*/
|
|
43
|
+
declare function injectSession({ context, user, domain, }: {
|
|
44
|
+
context: {
|
|
45
|
+
addCookies: (cookies: Array<Record<string, unknown>>) => Promise<void>;
|
|
46
|
+
};
|
|
47
|
+
user: TestUser;
|
|
48
|
+
domain?: string;
|
|
49
|
+
}): Promise<void>;
|
|
50
|
+
/**
|
|
51
|
+
* Delete all test users created during this run.
|
|
52
|
+
*
|
|
53
|
+
* Useful for mid-test cleanup or in `afterAll` hooks.
|
|
54
|
+
*/
|
|
55
|
+
declare function cleanup(): Promise<{
|
|
56
|
+
deleted: number;
|
|
57
|
+
}>;
|
|
58
|
+
|
|
59
|
+
export { type AuthGateSetupOptions, CreateTestUserOptions, TestUser, authgateSetup, authgateTeardown, cleanup, createTestUser, injectSession };
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { A as AuthGateTestConfig, C as CreateTestUserOptions, T as TestUser } from './client-DdLppI95.js';
|
|
2
|
+
export { b as AuthGateTest, c as TestSession } from './client-DdLppI95.js';
|
|
3
|
+
|
|
4
|
+
interface AuthGateSetupOptions extends AuthGateTestConfig {
|
|
5
|
+
cleanupOnStart?: boolean;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Initialise the AuthGate testing helpers.
|
|
9
|
+
*
|
|
10
|
+
* Call this once in your Playwright **global setup** file.
|
|
11
|
+
* It persists the config to a temporary JSON file so that worker processes
|
|
12
|
+
* spawned by Playwright can pick it up via {@link ensureInitialized}.
|
|
13
|
+
*
|
|
14
|
+
* @param options - API key, base URL, and optional `cleanupOnStart` flag.
|
|
15
|
+
*/
|
|
16
|
+
declare function authgateSetup(options: AuthGateSetupOptions): Promise<void>;
|
|
17
|
+
/**
|
|
18
|
+
* Tear down the AuthGate testing helpers.
|
|
19
|
+
*
|
|
20
|
+
* Call this in your Playwright **global teardown** file.
|
|
21
|
+
* It deletes all test users created during the run and removes the
|
|
22
|
+
* temporary state file.
|
|
23
|
+
*/
|
|
24
|
+
declare function authgateTeardown(): Promise<void>;
|
|
25
|
+
/**
|
|
26
|
+
* Create a test user via the AuthGate Testing API.
|
|
27
|
+
*
|
|
28
|
+
* Returns a {@link TestUser} with valid `token` and `refreshToken` that can
|
|
29
|
+
* be passed to {@link injectSession}.
|
|
30
|
+
*/
|
|
31
|
+
declare function createTestUser(options: CreateTestUserOptions): Promise<TestUser>;
|
|
32
|
+
/**
|
|
33
|
+
* Inject an authenticated session into a Playwright {@link BrowserContext}.
|
|
34
|
+
*
|
|
35
|
+
* Sets the encrypted session cookie and refresh-token cookie so that the
|
|
36
|
+
* browser context appears fully logged-in without going through the UI
|
|
37
|
+
* sign-in flow.
|
|
38
|
+
*
|
|
39
|
+
* @param params.context - A Playwright `BrowserContext` (or anything with `addCookies`).
|
|
40
|
+
* @param params.user - The {@link TestUser} returned by {@link createTestUser}.
|
|
41
|
+
* @param params.domain - Cookie domain (defaults to `"localhost"`).
|
|
42
|
+
*/
|
|
43
|
+
declare function injectSession({ context, user, domain, }: {
|
|
44
|
+
context: {
|
|
45
|
+
addCookies: (cookies: Array<Record<string, unknown>>) => Promise<void>;
|
|
46
|
+
};
|
|
47
|
+
user: TestUser;
|
|
48
|
+
domain?: string;
|
|
49
|
+
}): Promise<void>;
|
|
50
|
+
/**
|
|
51
|
+
* Delete all test users created during this run.
|
|
52
|
+
*
|
|
53
|
+
* Useful for mid-test cleanup or in `afterAll` hooks.
|
|
54
|
+
*/
|
|
55
|
+
declare function cleanup(): Promise<{
|
|
56
|
+
deleted: number;
|
|
57
|
+
}>;
|
|
58
|
+
|
|
59
|
+
export { type AuthGateSetupOptions, CreateTestUserOptions, TestUser, authgateSetup, authgateTeardown, cleanup, createTestUser, injectSession };
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AuthGateTest,
|
|
3
|
+
__require
|
|
4
|
+
} from "./chunk-VFBHRWNY.mjs";
|
|
5
|
+
|
|
6
|
+
// src/playwright.ts
|
|
7
|
+
import { createAuthGateClient } from "@auth-gate/core";
|
|
8
|
+
var STATE_FILE = ".authgate-test-state.json";
|
|
9
|
+
var _client = null;
|
|
10
|
+
var _coreClient = null;
|
|
11
|
+
var _config = null;
|
|
12
|
+
function getClient() {
|
|
13
|
+
if (!_client) {
|
|
14
|
+
throw new Error(
|
|
15
|
+
"AuthGate testing not initialized. Call authgateSetup() in your global setup first."
|
|
16
|
+
);
|
|
17
|
+
}
|
|
18
|
+
return _client;
|
|
19
|
+
}
|
|
20
|
+
function getCoreClient() {
|
|
21
|
+
if (!_coreClient) {
|
|
22
|
+
throw new Error(
|
|
23
|
+
"AuthGate testing not initialized. Call authgateSetup() in your global setup first."
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
return _coreClient;
|
|
27
|
+
}
|
|
28
|
+
async function authgateSetup(options) {
|
|
29
|
+
_config = { apiKey: options.apiKey, baseUrl: options.baseUrl };
|
|
30
|
+
_client = new AuthGateTest(_config);
|
|
31
|
+
_coreClient = createAuthGateClient({
|
|
32
|
+
apiKey: options.apiKey,
|
|
33
|
+
baseUrl: options.baseUrl
|
|
34
|
+
});
|
|
35
|
+
if (options.cleanupOnStart) {
|
|
36
|
+
await _client.cleanup();
|
|
37
|
+
}
|
|
38
|
+
const fs = await import("fs");
|
|
39
|
+
fs.writeFileSync(STATE_FILE, JSON.stringify(_config), "utf-8");
|
|
40
|
+
}
|
|
41
|
+
async function authgateTeardown() {
|
|
42
|
+
if (_client) {
|
|
43
|
+
await _client.cleanup();
|
|
44
|
+
}
|
|
45
|
+
const fs = await import("fs");
|
|
46
|
+
if (fs.existsSync(STATE_FILE)) {
|
|
47
|
+
fs.unlinkSync(STATE_FILE);
|
|
48
|
+
}
|
|
49
|
+
_client = null;
|
|
50
|
+
_coreClient = null;
|
|
51
|
+
_config = null;
|
|
52
|
+
}
|
|
53
|
+
function ensureInitialized() {
|
|
54
|
+
if (_client) return;
|
|
55
|
+
const fs = __require("fs");
|
|
56
|
+
if (fs.existsSync(STATE_FILE)) {
|
|
57
|
+
const config = JSON.parse(
|
|
58
|
+
fs.readFileSync(STATE_FILE, "utf-8")
|
|
59
|
+
);
|
|
60
|
+
_config = config;
|
|
61
|
+
_client = new AuthGateTest(config);
|
|
62
|
+
_coreClient = createAuthGateClient({
|
|
63
|
+
apiKey: config.apiKey,
|
|
64
|
+
baseUrl: config.baseUrl
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
async function createTestUser(options) {
|
|
69
|
+
ensureInitialized();
|
|
70
|
+
return getClient().createUser(options);
|
|
71
|
+
}
|
|
72
|
+
async function injectSession({
|
|
73
|
+
context,
|
|
74
|
+
user,
|
|
75
|
+
domain = "localhost"
|
|
76
|
+
}) {
|
|
77
|
+
ensureInitialized();
|
|
78
|
+
const client = getCoreClient();
|
|
79
|
+
const encryptedSession = await client.encryptSession({
|
|
80
|
+
id: user.id,
|
|
81
|
+
email: user.email,
|
|
82
|
+
phone: null,
|
|
83
|
+
name: user.name,
|
|
84
|
+
picture: null,
|
|
85
|
+
provider: "email"
|
|
86
|
+
});
|
|
87
|
+
await context.addCookies([
|
|
88
|
+
{
|
|
89
|
+
name: client.cookieName,
|
|
90
|
+
value: encryptedSession,
|
|
91
|
+
domain,
|
|
92
|
+
path: "/",
|
|
93
|
+
httpOnly: true,
|
|
94
|
+
secure: false,
|
|
95
|
+
sameSite: "Lax"
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
name: client.refreshTokenCookieName,
|
|
99
|
+
value: user.refreshToken,
|
|
100
|
+
domain,
|
|
101
|
+
path: "/",
|
|
102
|
+
httpOnly: true,
|
|
103
|
+
secure: false,
|
|
104
|
+
sameSite: "Lax"
|
|
105
|
+
}
|
|
106
|
+
]);
|
|
107
|
+
}
|
|
108
|
+
async function cleanup() {
|
|
109
|
+
ensureInitialized();
|
|
110
|
+
return getClient().cleanup();
|
|
111
|
+
}
|
|
112
|
+
export {
|
|
113
|
+
AuthGateTest,
|
|
114
|
+
authgateSetup,
|
|
115
|
+
authgateTeardown,
|
|
116
|
+
cleanup,
|
|
117
|
+
createTestUser,
|
|
118
|
+
injectSession
|
|
119
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@auth-gate/testing",
|
|
3
|
+
"version": "0.7.1",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"exports": {
|
|
6
|
+
".": {
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"import": "./dist/index.mjs",
|
|
9
|
+
"require": "./dist/index.cjs"
|
|
10
|
+
},
|
|
11
|
+
"./playwright": {
|
|
12
|
+
"types": "./dist/playwright.d.ts",
|
|
13
|
+
"import": "./dist/playwright.mjs",
|
|
14
|
+
"require": "./dist/playwright.cjs"
|
|
15
|
+
},
|
|
16
|
+
"./cypress": {
|
|
17
|
+
"types": "./dist/cypress.d.ts",
|
|
18
|
+
"import": "./dist/cypress.mjs",
|
|
19
|
+
"require": "./dist/cypress.cjs"
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"main": "./dist/index.cjs",
|
|
23
|
+
"module": "./dist/index.mjs",
|
|
24
|
+
"types": "./dist/index.d.ts",
|
|
25
|
+
"files": [
|
|
26
|
+
"dist"
|
|
27
|
+
],
|
|
28
|
+
"dependencies": {
|
|
29
|
+
"@auth-gate/core": "0.7.1"
|
|
30
|
+
},
|
|
31
|
+
"peerDependencies": {
|
|
32
|
+
"@playwright/test": ">=1.40",
|
|
33
|
+
"cypress": ">=12"
|
|
34
|
+
},
|
|
35
|
+
"peerDependenciesMeta": {
|
|
36
|
+
"@playwright/test": {
|
|
37
|
+
"optional": true
|
|
38
|
+
},
|
|
39
|
+
"cypress": {
|
|
40
|
+
"optional": true
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
"devDependencies": {
|
|
44
|
+
"@playwright/test": "^1.50.0",
|
|
45
|
+
"cypress": "^13.0.0",
|
|
46
|
+
"tsup": "^8.0.0",
|
|
47
|
+
"typescript": "^5"
|
|
48
|
+
},
|
|
49
|
+
"scripts": {
|
|
50
|
+
"build": "tsup",
|
|
51
|
+
"typecheck": "tsc --noEmit"
|
|
52
|
+
}
|
|
53
|
+
}
|