@emesoft_company/playwright-core 2.1.0

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.
Files changed (92) hide show
  1. package/README.md +62 -0
  2. package/dist/api/index.cjs +248 -0
  3. package/dist/api/index.cjs.map +1 -0
  4. package/dist/api/index.d.cts +12 -0
  5. package/dist/api/index.d.ts +12 -0
  6. package/dist/api/index.js +245 -0
  7. package/dist/api/index.js.map +1 -0
  8. package/dist/api-client-C_StjpPX.d.ts +58 -0
  9. package/dist/api-client-CpXo_NOU.d.cts +58 -0
  10. package/dist/auth/index.cjs +310 -0
  11. package/dist/auth/index.cjs.map +1 -0
  12. package/dist/auth/index.d.cts +98 -0
  13. package/dist/auth/index.d.ts +98 -0
  14. package/dist/auth/index.js +304 -0
  15. package/dist/auth/index.js.map +1 -0
  16. package/dist/config/index.cjs +268 -0
  17. package/dist/config/index.cjs.map +1 -0
  18. package/dist/config/index.d.cts +105 -0
  19. package/dist/config/index.d.ts +105 -0
  20. package/dist/config/index.js +254 -0
  21. package/dist/config/index.js.map +1 -0
  22. package/dist/data/index.cjs +59 -0
  23. package/dist/data/index.cjs.map +1 -0
  24. package/dist/data/index.d.cts +25 -0
  25. package/dist/data/index.d.ts +25 -0
  26. package/dist/data/index.js +50 -0
  27. package/dist/data/index.js.map +1 -0
  28. package/dist/di/index.cjs +47 -0
  29. package/dist/di/index.cjs.map +1 -0
  30. package/dist/di/index.d.cts +19 -0
  31. package/dist/di/index.d.ts +19 -0
  32. package/dist/di/index.js +45 -0
  33. package/dist/di/index.js.map +1 -0
  34. package/dist/errors/index.cjs +90 -0
  35. package/dist/errors/index.cjs.map +1 -0
  36. package/dist/errors/index.d.cts +38 -0
  37. package/dist/errors/index.d.ts +38 -0
  38. package/dist/errors/index.js +83 -0
  39. package/dist/errors/index.js.map +1 -0
  40. package/dist/expect/index.cjs +36 -0
  41. package/dist/expect/index.cjs.map +1 -0
  42. package/dist/expect/index.d.cts +30 -0
  43. package/dist/expect/index.d.ts +30 -0
  44. package/dist/expect/index.js +34 -0
  45. package/dist/expect/index.js.map +1 -0
  46. package/dist/fixtures/index.cjs +660 -0
  47. package/dist/fixtures/index.cjs.map +1 -0
  48. package/dist/fixtures/index.d.cts +68 -0
  49. package/dist/fixtures/index.d.ts +68 -0
  50. package/dist/fixtures/index.js +651 -0
  51. package/dist/fixtures/index.js.map +1 -0
  52. package/dist/index.cjs +1322 -0
  53. package/dist/index.cjs.map +1 -0
  54. package/dist/index.d.cts +21 -0
  55. package/dist/index.d.ts +21 -0
  56. package/dist/index.js +1248 -0
  57. package/dist/index.js.map +1 -0
  58. package/dist/logging/index.cjs +32 -0
  59. package/dist/logging/index.cjs.map +1 -0
  60. package/dist/logging/index.d.cts +18 -0
  61. package/dist/logging/index.d.ts +18 -0
  62. package/dist/logging/index.js +25 -0
  63. package/dist/logging/index.js.map +1 -0
  64. package/dist/reporting/index.cjs +59 -0
  65. package/dist/reporting/index.cjs.map +1 -0
  66. package/dist/reporting/index.d.cts +63 -0
  67. package/dist/reporting/index.d.ts +63 -0
  68. package/dist/reporting/index.js +52 -0
  69. package/dist/reporting/index.js.map +1 -0
  70. package/dist/retry-XqnSC8YL.d.cts +27 -0
  71. package/dist/retry-XqnSC8YL.d.ts +27 -0
  72. package/dist/schema-y5w2hbT-.d.cts +292 -0
  73. package/dist/schema-y5w2hbT-.d.ts +292 -0
  74. package/dist/types-CbWnSYEK.d.cts +5 -0
  75. package/dist/types-CbWnSYEK.d.ts +5 -0
  76. package/dist/types-CopwwpSW.d.cts +8 -0
  77. package/dist/types-CopwwpSW.d.ts +8 -0
  78. package/dist/types-hInbkPXf.d.cts +59 -0
  79. package/dist/types-hInbkPXf.d.ts +59 -0
  80. package/dist/ui/index.cjs +366 -0
  81. package/dist/ui/index.cjs.map +1 -0
  82. package/dist/ui/index.d.cts +190 -0
  83. package/dist/ui/index.d.ts +190 -0
  84. package/dist/ui/index.js +348 -0
  85. package/dist/ui/index.js.map +1 -0
  86. package/dist/utils/index.cjs +72 -0
  87. package/dist/utils/index.cjs.map +1 -0
  88. package/dist/utils/index.d.cts +27 -0
  89. package/dist/utils/index.d.ts +27 -0
  90. package/dist/utils/index.js +66 -0
  91. package/dist/utils/index.js.map +1 -0
  92. package/package.json +133 -0
@@ -0,0 +1,45 @@
1
+ // src/errors/app-error.ts
2
+ var AppError = class extends Error {
3
+ code;
4
+ context;
5
+ constructor(message, options) {
6
+ super(message, { cause: options.cause });
7
+ this.name = new.target.name;
8
+ this.code = options.code;
9
+ this.context = options.context;
10
+ Object.setPrototypeOf(this, new.target.prototype);
11
+ }
12
+ };
13
+
14
+ // src/di/container.ts
15
+ var ServiceContainer = class {
16
+ factories = /* @__PURE__ */ new Map();
17
+ singletons = /* @__PURE__ */ new Map();
18
+ register(key, factory) {
19
+ this.factories.set(key, factory);
20
+ this.singletons.delete(key);
21
+ }
22
+ /** Replaces an existing registration — this is how a project overrides a core-provided service. */
23
+ override(key, factory) {
24
+ this.register(key, factory);
25
+ }
26
+ resolve(key) {
27
+ if (this.singletons.has(key)) {
28
+ return this.singletons.get(key);
29
+ }
30
+ const factory = this.factories.get(key);
31
+ if (!factory) {
32
+ throw new AppError(`No provider registered for service "${key}"`, { code: "DI_UNRESOLVED" });
33
+ }
34
+ const instance = factory(this);
35
+ this.singletons.set(key, instance);
36
+ return instance;
37
+ }
38
+ has(key) {
39
+ return this.factories.has(key);
40
+ }
41
+ };
42
+
43
+ export { ServiceContainer };
44
+ //# sourceMappingURL=index.js.map
45
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/errors/app-error.ts","../../src/di/container.ts"],"names":[],"mappings":";AAWO,IAAM,QAAA,GAAN,cAAuB,KAAA,CAAM;AAAA,EACzB,IAAA;AAAA,EACA,OAAA;AAAA,EAET,WAAA,CAAY,SAAiB,OAAA,EAA0B;AACrD,IAAA,KAAA,CAAM,OAAA,EAAS,EAAE,KAAA,EAAO,OAAA,CAAQ,OAAO,CAAA;AACvC,IAAA,IAAA,CAAK,OAAO,GAAA,CAAA,MAAA,CAAW,IAAA;AACvB,IAAA,IAAA,CAAK,OAAO,OAAA,CAAQ,IAAA;AACpB,IAAA,IAAA,CAAK,UAAU,OAAA,CAAQ,OAAA;AACvB,IAAA,MAAA,CAAO,cAAA,CAAe,IAAA,EAAM,GAAA,CAAA,MAAA,CAAW,SAAS,CAAA;AAAA,EAClD;AACF,CAAA;;;ACXO,IAAM,mBAAN,MAAuB;AAAA,EACX,SAAA,uBAAgB,GAAA,EAA8B;AAAA,EAC9C,UAAA,uBAAiB,GAAA,EAAqB;AAAA,EAEvD,QAAA,CAAY,KAAa,OAAA,EAA2B;AAClD,IAAA,IAAA,CAAK,SAAA,CAAU,GAAA,CAAI,GAAA,EAAK,OAA2B,CAAA;AACnD,IAAA,IAAA,CAAK,UAAA,CAAW,OAAO,GAAG,CAAA;AAAA,EAC5B;AAAA;AAAA,EAGA,QAAA,CAAY,KAAa,OAAA,EAA2B;AAClD,IAAA,IAAA,CAAK,QAAA,CAAS,KAAK,OAAO,CAAA;AAAA,EAC5B;AAAA,EAEA,QAAW,GAAA,EAAgB;AACzB,IAAA,IAAI,IAAA,CAAK,UAAA,CAAW,GAAA,CAAI,GAAG,CAAA,EAAG;AAC5B,MAAA,OAAO,IAAA,CAAK,UAAA,CAAW,GAAA,CAAI,GAAG,CAAA;AAAA,IAChC;AACA,IAAA,MAAM,OAAA,GAAU,IAAA,CAAK,SAAA,CAAU,GAAA,CAAI,GAAG,CAAA;AACtC,IAAA,IAAI,CAAC,OAAA,EAAS;AACZ,MAAA,MAAM,IAAI,SAAS,CAAA,oCAAA,EAAuC,GAAG,KAAK,EAAE,IAAA,EAAM,iBAAiB,CAAA;AAAA,IAC7F;AACA,IAAA,MAAM,QAAA,GAAW,QAAQ,IAAI,CAAA;AAC7B,IAAA,IAAA,CAAK,UAAA,CAAW,GAAA,CAAI,GAAA,EAAK,QAAQ,CAAA;AACjC,IAAA,OAAO,QAAA;AAAA,EACT;AAAA,EAEA,IAAI,GAAA,EAAsB;AACxB,IAAA,OAAO,IAAA,CAAK,SAAA,CAAU,GAAA,CAAI,GAAG,CAAA;AAAA,EAC/B;AACF","file":"index.js","sourcesContent":["export interface AppErrorOptions {\n code: string;\n cause?: unknown;\n context?: Record<string, unknown>;\n}\n\n/**\n * Base error class for the framework. Every error thrown by core carries a\n * machine-readable `code` and optional `context`, so callers can branch on\n * `error.code` instead of parsing messages.\n */\nexport class AppError extends Error {\n readonly code: string;\n readonly context?: Record<string, unknown>;\n\n constructor(message: string, options: AppErrorOptions) {\n super(message, { cause: options.cause });\n this.name = new.target.name;\n this.code = options.code;\n this.context = options.context;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\nexport class ConfigValidationError extends AppError {\n constructor(message: string, issues: unknown, context?: Record<string, unknown>) {\n super(message, { code: \"CONFIG_VALIDATION_ERROR\", context: { issues, ...context } });\n }\n}\n\nexport class ApiError extends AppError {\n readonly status?: number;\n readonly method?: string;\n readonly url?: string;\n\n constructor(\n message: string,\n options: AppErrorOptions & { status?: number; method?: string; url?: string },\n ) {\n super(message, options);\n this.status = options.status;\n this.method = options.method;\n this.url = options.url;\n }\n}\n\nexport class AuthError extends AppError {\n constructor(message: string, options: Omit<AppErrorOptions, \"code\"> = {}) {\n super(message, { code: \"AUTH_ERROR\", ...options });\n }\n}\n\nexport class ConfigMissingError extends AppError {\n constructor(name: string) {\n super(`Required environment variable \"${name}\" is not set`, {\n code: \"ENV_VAR_MISSING\",\n context: { name },\n });\n }\n}\n","import { AppError } from \"../errors/app-error.js\";\n\nexport type Factory<T> = (container: ServiceContainer) => T;\n\n/**\n * Minimal typed service locator used internally by core (and available to projects)\n * for wiring services that aren't naturally expressed as Playwright fixtures — e.g.\n * a token provider shared by both the API client and UI auth setup. Playwright's own\n * `test.extend()` remains the primary DI mechanism for anything test-scoped; this\n * container is for singletons that outlive a single fixture chain.\n */\nexport class ServiceContainer {\n private readonly factories = new Map<string, Factory<unknown>>();\n private readonly singletons = new Map<string, unknown>();\n\n register<T>(key: string, factory: Factory<T>): void {\n this.factories.set(key, factory as Factory<unknown>);\n this.singletons.delete(key);\n }\n\n /** Replaces an existing registration — this is how a project overrides a core-provided service. */\n override<T>(key: string, factory: Factory<T>): void {\n this.register(key, factory);\n }\n\n resolve<T>(key: string): T {\n if (this.singletons.has(key)) {\n return this.singletons.get(key) as T;\n }\n const factory = this.factories.get(key);\n if (!factory) {\n throw new AppError(`No provider registered for service \"${key}\"`, { code: \"DI_UNRESOLVED\" });\n }\n const instance = factory(this);\n this.singletons.set(key, instance);\n return instance as T;\n }\n\n has(key: string): boolean {\n return this.factories.has(key);\n }\n}\n"]}
@@ -0,0 +1,90 @@
1
+ 'use strict';
2
+
3
+ // src/errors/app-error.ts
4
+ var AppError = class extends Error {
5
+ code;
6
+ context;
7
+ constructor(message, options) {
8
+ super(message, { cause: options.cause });
9
+ this.name = new.target.name;
10
+ this.code = options.code;
11
+ this.context = options.context;
12
+ Object.setPrototypeOf(this, new.target.prototype);
13
+ }
14
+ };
15
+ var ConfigValidationError = class extends AppError {
16
+ constructor(message, issues, context) {
17
+ super(message, { code: "CONFIG_VALIDATION_ERROR", context: { issues, ...context } });
18
+ }
19
+ };
20
+ var ApiError = class extends AppError {
21
+ status;
22
+ method;
23
+ url;
24
+ constructor(message, options) {
25
+ super(message, options);
26
+ this.status = options.status;
27
+ this.method = options.method;
28
+ this.url = options.url;
29
+ }
30
+ };
31
+ var AuthError = class extends AppError {
32
+ constructor(message, options = {}) {
33
+ super(message, { code: "AUTH_ERROR", ...options });
34
+ }
35
+ };
36
+ var ConfigMissingError = class extends AppError {
37
+ constructor(name) {
38
+ super(`Required environment variable "${name}" is not set`, {
39
+ code: "ENV_VAR_MISSING",
40
+ context: { name }
41
+ });
42
+ }
43
+ };
44
+
45
+ // src/utils/sleep.ts
46
+ function sleep(ms) {
47
+ return new Promise((resolve) => setTimeout(resolve, ms));
48
+ }
49
+
50
+ // src/errors/retry.ts
51
+ function backoffDelay(attempt, minDelayMs, maxDelayMs, factor) {
52
+ const exponential = minDelayMs * factor ** (attempt - 1);
53
+ const jitter = Math.random() * minDelayMs;
54
+ return Math.min(exponential + jitter, maxDelayMs);
55
+ }
56
+ async function withRetry(fn, options = {}) {
57
+ const {
58
+ retries = 2,
59
+ minDelayMs = 200,
60
+ maxDelayMs = 5e3,
61
+ factor = 2,
62
+ retryOn = () => true,
63
+ onRetry,
64
+ onGiveUp
65
+ } = options;
66
+ const maxAttempts = retries + 1;
67
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
68
+ try {
69
+ return await fn();
70
+ } catch (error) {
71
+ const isLastAttempt = attempt >= maxAttempts;
72
+ if (isLastAttempt || !retryOn(error)) {
73
+ onGiveUp?.(error, attempt);
74
+ throw error;
75
+ }
76
+ onRetry?.(error, attempt);
77
+ await sleep(backoffDelay(attempt, minDelayMs, maxDelayMs, factor));
78
+ }
79
+ }
80
+ throw new Error("withRetry: unreachable state");
81
+ }
82
+
83
+ exports.ApiError = ApiError;
84
+ exports.AppError = AppError;
85
+ exports.AuthError = AuthError;
86
+ exports.ConfigMissingError = ConfigMissingError;
87
+ exports.ConfigValidationError = ConfigValidationError;
88
+ exports.withRetry = withRetry;
89
+ //# sourceMappingURL=index.cjs.map
90
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/errors/app-error.ts","../../src/utils/sleep.ts","../../src/errors/retry.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["export interface AppErrorOptions {\n code: string;\n cause?: unknown;\n context?: Record<string, unknown>;\n}\n\n/**\n * Base error class for the framework. Every error thrown by core carries a\n * machine-readable `code` and optional `context`, so callers can branch on\n * `error.code` instead of parsing messages.\n */\nexport class AppError extends Error {\n readonly code: string;\n readonly context?: Record<string, unknown>;\n\n constructor(message: string, options: AppErrorOptions) {\n super(message, { cause: options.cause });\n this.name = new.target.name;\n this.code = options.code;\n this.context = options.context;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\nexport class ConfigValidationError extends AppError {\n constructor(message: string, issues: unknown, context?: Record<string, unknown>) {\n super(message, { code: \"CONFIG_VALIDATION_ERROR\", context: { issues, ...context } });\n }\n}\n\nexport class ApiError extends AppError {\n readonly status?: number;\n readonly method?: string;\n readonly url?: string;\n\n constructor(\n message: string,\n options: AppErrorOptions & { status?: number; method?: string; url?: string },\n ) {\n super(message, options);\n this.status = options.status;\n this.method = options.method;\n this.url = options.url;\n }\n}\n\nexport class AuthError extends AppError {\n constructor(message: string, options: Omit<AppErrorOptions, \"code\"> = {}) {\n super(message, { code: \"AUTH_ERROR\", ...options });\n }\n}\n\nexport class ConfigMissingError extends AppError {\n constructor(name: string) {\n super(`Required environment variable \"${name}\" is not set`, {\n code: \"ENV_VAR_MISSING\",\n context: { name },\n });\n }\n}\n","export function sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n","import { sleep } from \"../utils/sleep.js\";\n\nexport interface RetryOptions {\n /** Number of retry attempts after the initial try. Default: 2. */\n retries?: number;\n minDelayMs?: number;\n maxDelayMs?: number;\n /** Exponential backoff factor. Default: 2. */\n factor?: number;\n /** Return true to retry this error, false to fail fast. Default: retry everything. */\n retryOn?: (error: unknown) => boolean;\n /** Called before each retry (not before the first attempt). */\n onRetry?: (error: unknown, attempt: number) => void;\n /** Called once when giving up, with the total number of attempts made. */\n onGiveUp?: (error: unknown, attempts: number) => void;\n}\n\nfunction backoffDelay(attempt: number, minDelayMs: number, maxDelayMs: number, factor: number): number {\n const exponential = minDelayMs * factor ** (attempt - 1);\n const jitter = Math.random() * minDelayMs;\n return Math.min(exponential + jitter, maxDelayMs);\n}\n\n/**\n * Runs `fn` with exponential-backoff retry. Used for both flaky API calls and\n * flaky UI actions so the retry policy stays consistent across the framework.\n *\n * Always rethrows the ORIGINAL error — whether it failed fast (`retryOn` returned\n * false) or exhausted its retries. That's what makes `catch (e) { e instanceof ApiError }`\n * and `expect(...).rejects.toThrow(ApiError)` work in tests; wrapping the error in a\n * retry-specific type would hide the only thing the caller actually wants to assert on.\n * Use `onGiveUp` if you need the attempt count.\n */\nexport async function withRetry<T>(fn: () => Promise<T>, options: RetryOptions = {}): Promise<T> {\n const {\n retries = 2,\n minDelayMs = 200,\n maxDelayMs = 5_000,\n factor = 2,\n retryOn = () => true,\n onRetry,\n onGiveUp,\n } = options;\n\n const maxAttempts = retries + 1;\n\n for (let attempt = 1; attempt <= maxAttempts; attempt++) {\n try {\n return await fn();\n } catch (error) {\n const isLastAttempt = attempt >= maxAttempts;\n if (isLastAttempt || !retryOn(error)) {\n onGiveUp?.(error, attempt);\n throw error;\n }\n onRetry?.(error, attempt);\n await sleep(backoffDelay(attempt, minDelayMs, maxDelayMs, factor));\n }\n }\n\n // Unreachable: the loop either returns or throws.\n throw new Error(\"withRetry: unreachable state\");\n}\n"]}
@@ -0,0 +1,38 @@
1
+ export { R as RetryOptions, w as withRetry } from '../retry-XqnSC8YL.cjs';
2
+
3
+ interface AppErrorOptions {
4
+ code: string;
5
+ cause?: unknown;
6
+ context?: Record<string, unknown>;
7
+ }
8
+ /**
9
+ * Base error class for the framework. Every error thrown by core carries a
10
+ * machine-readable `code` and optional `context`, so callers can branch on
11
+ * `error.code` instead of parsing messages.
12
+ */
13
+ declare class AppError extends Error {
14
+ readonly code: string;
15
+ readonly context?: Record<string, unknown>;
16
+ constructor(message: string, options: AppErrorOptions);
17
+ }
18
+ declare class ConfigValidationError extends AppError {
19
+ constructor(message: string, issues: unknown, context?: Record<string, unknown>);
20
+ }
21
+ declare class ApiError extends AppError {
22
+ readonly status?: number;
23
+ readonly method?: string;
24
+ readonly url?: string;
25
+ constructor(message: string, options: AppErrorOptions & {
26
+ status?: number;
27
+ method?: string;
28
+ url?: string;
29
+ });
30
+ }
31
+ declare class AuthError extends AppError {
32
+ constructor(message: string, options?: Omit<AppErrorOptions, "code">);
33
+ }
34
+ declare class ConfigMissingError extends AppError {
35
+ constructor(name: string);
36
+ }
37
+
38
+ export { ApiError, AppError, type AppErrorOptions, AuthError, ConfigMissingError, ConfigValidationError };
@@ -0,0 +1,38 @@
1
+ export { R as RetryOptions, w as withRetry } from '../retry-XqnSC8YL.js';
2
+
3
+ interface AppErrorOptions {
4
+ code: string;
5
+ cause?: unknown;
6
+ context?: Record<string, unknown>;
7
+ }
8
+ /**
9
+ * Base error class for the framework. Every error thrown by core carries a
10
+ * machine-readable `code` and optional `context`, so callers can branch on
11
+ * `error.code` instead of parsing messages.
12
+ */
13
+ declare class AppError extends Error {
14
+ readonly code: string;
15
+ readonly context?: Record<string, unknown>;
16
+ constructor(message: string, options: AppErrorOptions);
17
+ }
18
+ declare class ConfigValidationError extends AppError {
19
+ constructor(message: string, issues: unknown, context?: Record<string, unknown>);
20
+ }
21
+ declare class ApiError extends AppError {
22
+ readonly status?: number;
23
+ readonly method?: string;
24
+ readonly url?: string;
25
+ constructor(message: string, options: AppErrorOptions & {
26
+ status?: number;
27
+ method?: string;
28
+ url?: string;
29
+ });
30
+ }
31
+ declare class AuthError extends AppError {
32
+ constructor(message: string, options?: Omit<AppErrorOptions, "code">);
33
+ }
34
+ declare class ConfigMissingError extends AppError {
35
+ constructor(name: string);
36
+ }
37
+
38
+ export { ApiError, AppError, type AppErrorOptions, AuthError, ConfigMissingError, ConfigValidationError };
@@ -0,0 +1,83 @@
1
+ // src/errors/app-error.ts
2
+ var AppError = class extends Error {
3
+ code;
4
+ context;
5
+ constructor(message, options) {
6
+ super(message, { cause: options.cause });
7
+ this.name = new.target.name;
8
+ this.code = options.code;
9
+ this.context = options.context;
10
+ Object.setPrototypeOf(this, new.target.prototype);
11
+ }
12
+ };
13
+ var ConfigValidationError = class extends AppError {
14
+ constructor(message, issues, context) {
15
+ super(message, { code: "CONFIG_VALIDATION_ERROR", context: { issues, ...context } });
16
+ }
17
+ };
18
+ var ApiError = class extends AppError {
19
+ status;
20
+ method;
21
+ url;
22
+ constructor(message, options) {
23
+ super(message, options);
24
+ this.status = options.status;
25
+ this.method = options.method;
26
+ this.url = options.url;
27
+ }
28
+ };
29
+ var AuthError = class extends AppError {
30
+ constructor(message, options = {}) {
31
+ super(message, { code: "AUTH_ERROR", ...options });
32
+ }
33
+ };
34
+ var ConfigMissingError = class extends AppError {
35
+ constructor(name) {
36
+ super(`Required environment variable "${name}" is not set`, {
37
+ code: "ENV_VAR_MISSING",
38
+ context: { name }
39
+ });
40
+ }
41
+ };
42
+
43
+ // src/utils/sleep.ts
44
+ function sleep(ms) {
45
+ return new Promise((resolve) => setTimeout(resolve, ms));
46
+ }
47
+
48
+ // src/errors/retry.ts
49
+ function backoffDelay(attempt, minDelayMs, maxDelayMs, factor) {
50
+ const exponential = minDelayMs * factor ** (attempt - 1);
51
+ const jitter = Math.random() * minDelayMs;
52
+ return Math.min(exponential + jitter, maxDelayMs);
53
+ }
54
+ async function withRetry(fn, options = {}) {
55
+ const {
56
+ retries = 2,
57
+ minDelayMs = 200,
58
+ maxDelayMs = 5e3,
59
+ factor = 2,
60
+ retryOn = () => true,
61
+ onRetry,
62
+ onGiveUp
63
+ } = options;
64
+ const maxAttempts = retries + 1;
65
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
66
+ try {
67
+ return await fn();
68
+ } catch (error) {
69
+ const isLastAttempt = attempt >= maxAttempts;
70
+ if (isLastAttempt || !retryOn(error)) {
71
+ onGiveUp?.(error, attempt);
72
+ throw error;
73
+ }
74
+ onRetry?.(error, attempt);
75
+ await sleep(backoffDelay(attempt, minDelayMs, maxDelayMs, factor));
76
+ }
77
+ }
78
+ throw new Error("withRetry: unreachable state");
79
+ }
80
+
81
+ export { ApiError, AppError, AuthError, ConfigMissingError, ConfigValidationError, withRetry };
82
+ //# sourceMappingURL=index.js.map
83
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/errors/app-error.ts","../../src/utils/sleep.ts","../../src/errors/retry.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["export interface AppErrorOptions {\n code: string;\n cause?: unknown;\n context?: Record<string, unknown>;\n}\n\n/**\n * Base error class for the framework. Every error thrown by core carries a\n * machine-readable `code` and optional `context`, so callers can branch on\n * `error.code` instead of parsing messages.\n */\nexport class AppError extends Error {\n readonly code: string;\n readonly context?: Record<string, unknown>;\n\n constructor(message: string, options: AppErrorOptions) {\n super(message, { cause: options.cause });\n this.name = new.target.name;\n this.code = options.code;\n this.context = options.context;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\nexport class ConfigValidationError extends AppError {\n constructor(message: string, issues: unknown, context?: Record<string, unknown>) {\n super(message, { code: \"CONFIG_VALIDATION_ERROR\", context: { issues, ...context } });\n }\n}\n\nexport class ApiError extends AppError {\n readonly status?: number;\n readonly method?: string;\n readonly url?: string;\n\n constructor(\n message: string,\n options: AppErrorOptions & { status?: number; method?: string; url?: string },\n ) {\n super(message, options);\n this.status = options.status;\n this.method = options.method;\n this.url = options.url;\n }\n}\n\nexport class AuthError extends AppError {\n constructor(message: string, options: Omit<AppErrorOptions, \"code\"> = {}) {\n super(message, { code: \"AUTH_ERROR\", ...options });\n }\n}\n\nexport class ConfigMissingError extends AppError {\n constructor(name: string) {\n super(`Required environment variable \"${name}\" is not set`, {\n code: \"ENV_VAR_MISSING\",\n context: { name },\n });\n }\n}\n","export function sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n","import { sleep } from \"../utils/sleep.js\";\n\nexport interface RetryOptions {\n /** Number of retry attempts after the initial try. Default: 2. */\n retries?: number;\n minDelayMs?: number;\n maxDelayMs?: number;\n /** Exponential backoff factor. Default: 2. */\n factor?: number;\n /** Return true to retry this error, false to fail fast. Default: retry everything. */\n retryOn?: (error: unknown) => boolean;\n /** Called before each retry (not before the first attempt). */\n onRetry?: (error: unknown, attempt: number) => void;\n /** Called once when giving up, with the total number of attempts made. */\n onGiveUp?: (error: unknown, attempts: number) => void;\n}\n\nfunction backoffDelay(attempt: number, minDelayMs: number, maxDelayMs: number, factor: number): number {\n const exponential = minDelayMs * factor ** (attempt - 1);\n const jitter = Math.random() * minDelayMs;\n return Math.min(exponential + jitter, maxDelayMs);\n}\n\n/**\n * Runs `fn` with exponential-backoff retry. Used for both flaky API calls and\n * flaky UI actions so the retry policy stays consistent across the framework.\n *\n * Always rethrows the ORIGINAL error — whether it failed fast (`retryOn` returned\n * false) or exhausted its retries. That's what makes `catch (e) { e instanceof ApiError }`\n * and `expect(...).rejects.toThrow(ApiError)` work in tests; wrapping the error in a\n * retry-specific type would hide the only thing the caller actually wants to assert on.\n * Use `onGiveUp` if you need the attempt count.\n */\nexport async function withRetry<T>(fn: () => Promise<T>, options: RetryOptions = {}): Promise<T> {\n const {\n retries = 2,\n minDelayMs = 200,\n maxDelayMs = 5_000,\n factor = 2,\n retryOn = () => true,\n onRetry,\n onGiveUp,\n } = options;\n\n const maxAttempts = retries + 1;\n\n for (let attempt = 1; attempt <= maxAttempts; attempt++) {\n try {\n return await fn();\n } catch (error) {\n const isLastAttempt = attempt >= maxAttempts;\n if (isLastAttempt || !retryOn(error)) {\n onGiveUp?.(error, attempt);\n throw error;\n }\n onRetry?.(error, attempt);\n await sleep(backoffDelay(attempt, minDelayMs, maxDelayMs, factor));\n }\n }\n\n // Unreachable: the loop either returns or throws.\n throw new Error(\"withRetry: unreachable state\");\n}\n"]}
@@ -0,0 +1,36 @@
1
+ 'use strict';
2
+
3
+ var test = require('@playwright/test');
4
+
5
+ // src/expect/matchers.ts
6
+ var expect = test.expect.extend({
7
+ /**
8
+ * Asserts the status of an `ApiResponse` from `apiClient.send()`, printing the body on
9
+ * failure — otherwise a wrong status tells you nothing about why.
10
+ */
11
+ toHaveStatus(received, expected) {
12
+ const pass = received.status === expected;
13
+ return {
14
+ pass,
15
+ name: "toHaveStatus",
16
+ expected,
17
+ actual: received.status,
18
+ message: () => pass ? `Expected status not to be ${expected}` : `Expected ${received.method} ${received.url} to return ${expected}, got ${received.status}
19
+ Body: ${JSON.stringify(received.data, null, 2)}`
20
+ };
21
+ },
22
+ /** Asserts a value matches a zod schema, listing the exact field-level issues on failure. */
23
+ toMatchSchema(received, schema) {
24
+ const result = schema.safeParse(received);
25
+ return {
26
+ pass: result.success,
27
+ name: "toMatchSchema",
28
+ message: () => result.success ? "Expected value not to match the schema" : `Value did not match the schema:
29
+ ${result.error.issues.map((issue) => ` - ${issue.path.join(".") || "(root)"}: ${issue.message}`).join("\n")}`
30
+ };
31
+ }
32
+ });
33
+
34
+ exports.expect = expect;
35
+ //# sourceMappingURL=index.cjs.map
36
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/expect/matchers.ts"],"names":["baseExpect"],"mappings":";;;;;AASO,IAAM,MAAA,GAASA,YAAW,MAAA,CAAO;AAAA;AAAA;AAAA;AAAA;AAAA,EAKtC,YAAA,CAAa,UAAgC,QAAA,EAAkB;AAC7D,IAAA,MAAM,IAAA,GAAO,SAAS,MAAA,KAAW,QAAA;AACjC,IAAA,OAAO;AAAA,MACL,IAAA;AAAA,MACA,IAAA,EAAM,cAAA;AAAA,MACN,QAAA;AAAA,MACA,QAAQ,QAAA,CAAS,MAAA;AAAA,MACjB,SAAS,MACP,IAAA,GACI,CAAA,0BAAA,EAA6B,QAAQ,KACrC,CAAA,SAAA,EAAY,QAAA,CAAS,MAAM,CAAA,CAAA,EAAI,SAAS,GAAG,CAAA,WAAA,EAAc,QAAQ,CAAA,MAAA,EAAS,SAAS,MAAM;AAAA,MAAA,EAChF,KAAK,SAAA,CAAU,QAAA,CAAS,IAAA,EAAM,IAAA,EAAM,CAAC,CAAC,CAAA;AAAA,KACvD;AAAA,EACF,CAAA;AAAA;AAAA,EAGA,aAAA,CAAc,UAAmB,MAAA,EAA0B;AACzD,IAAA,MAAM,MAAA,GAAS,MAAA,CAAO,SAAA,CAAU,QAAQ,CAAA;AACxC,IAAA,OAAO;AAAA,MACL,MAAM,MAAA,CAAO,OAAA;AAAA,MACb,IAAA,EAAM,eAAA;AAAA,MACN,OAAA,EAAS,MACP,MAAA,CAAO,OAAA,GACH,wCAAA,GACA,CAAA;AAAA,EAAoC,MAAA,CAAO,MAAM,MAAA,CAC9C,GAAA,CAAI,CAAC,KAAA,KAAU,CAAA,IAAA,EAAO,MAAM,IAAA,CAAK,IAAA,CAAK,GAAG,CAAA,IAAK,QAAQ,KAAK,KAAA,CAAM,OAAO,EAAE,CAAA,CAC1E,IAAA,CAAK,IAAI,CAAC,CAAA;AAAA,KACrB;AAAA,EACF;AACF,CAAC","file":"index.cjs","sourcesContent":["import { expect as baseExpect } from \"@playwright/test\";\nimport type { ZodType } from \"zod\";\nimport type { ApiResponse } from \"../api/types.js\";\n\n/**\n * `expect` with a few framework-specific matchers added. Projects get these automatically by\n * importing `expect` from `@emesoft_company/playwright-core/fixtures` (or their own `fixtures/index.ts`),\n * so there's nothing to register per project.\n */\nexport const expect = baseExpect.extend({\n /**\n * Asserts the status of an `ApiResponse` from `apiClient.send()`, printing the body on\n * failure — otherwise a wrong status tells you nothing about why.\n */\n toHaveStatus(received: ApiResponse<unknown>, expected: number) {\n const pass = received.status === expected;\n return {\n pass,\n name: \"toHaveStatus\",\n expected,\n actual: received.status,\n message: () =>\n pass\n ? `Expected status not to be ${expected}`\n : `Expected ${received.method} ${received.url} to return ${expected}, got ${received.status}\\n` +\n `Body: ${JSON.stringify(received.data, null, 2)}`,\n };\n },\n\n /** Asserts a value matches a zod schema, listing the exact field-level issues on failure. */\n toMatchSchema(received: unknown, schema: ZodType<unknown>) {\n const result = schema.safeParse(received);\n return {\n pass: result.success,\n name: \"toMatchSchema\",\n message: () =>\n result.success\n ? \"Expected value not to match the schema\"\n : `Value did not match the schema:\\n${result.error.issues\n .map((issue) => ` - ${issue.path.join(\".\") || \"(root)\"}: ${issue.message}`)\n .join(\"\\n\")}`,\n };\n },\n});\n"]}
@@ -0,0 +1,30 @@
1
+ import * as _playwright_test from '@playwright/test';
2
+ import { ZodType } from 'zod';
3
+ import { b as ApiResponse } from '../types-hInbkPXf.cjs';
4
+
5
+ /**
6
+ * `expect` with a few framework-specific matchers added. Projects get these automatically by
7
+ * importing `expect` from `@emesoft_company/playwright-core/fixtures` (or their own `fixtures/index.ts`),
8
+ * so there's nothing to register per project.
9
+ */
10
+ declare const expect: _playwright_test.Expect<{
11
+ /**
12
+ * Asserts the status of an `ApiResponse` from `apiClient.send()`, printing the body on
13
+ * failure — otherwise a wrong status tells you nothing about why.
14
+ */
15
+ toHaveStatus(this: _playwright_test.ExpectMatcherState, received: ApiResponse<unknown>, expected: number): {
16
+ pass: boolean;
17
+ name: string;
18
+ expected: number;
19
+ actual: number;
20
+ message: () => string;
21
+ };
22
+ /** Asserts a value matches a zod schema, listing the exact field-level issues on failure. */
23
+ toMatchSchema(this: _playwright_test.ExpectMatcherState, received: unknown, schema: ZodType<unknown>): {
24
+ pass: boolean;
25
+ name: string;
26
+ message: () => string;
27
+ };
28
+ }>;
29
+
30
+ export { expect };
@@ -0,0 +1,30 @@
1
+ import * as _playwright_test from '@playwright/test';
2
+ import { ZodType } from 'zod';
3
+ import { b as ApiResponse } from '../types-hInbkPXf.js';
4
+
5
+ /**
6
+ * `expect` with a few framework-specific matchers added. Projects get these automatically by
7
+ * importing `expect` from `@emesoft_company/playwright-core/fixtures` (or their own `fixtures/index.ts`),
8
+ * so there's nothing to register per project.
9
+ */
10
+ declare const expect: _playwright_test.Expect<{
11
+ /**
12
+ * Asserts the status of an `ApiResponse` from `apiClient.send()`, printing the body on
13
+ * failure — otherwise a wrong status tells you nothing about why.
14
+ */
15
+ toHaveStatus(this: _playwright_test.ExpectMatcherState, received: ApiResponse<unknown>, expected: number): {
16
+ pass: boolean;
17
+ name: string;
18
+ expected: number;
19
+ actual: number;
20
+ message: () => string;
21
+ };
22
+ /** Asserts a value matches a zod schema, listing the exact field-level issues on failure. */
23
+ toMatchSchema(this: _playwright_test.ExpectMatcherState, received: unknown, schema: ZodType<unknown>): {
24
+ pass: boolean;
25
+ name: string;
26
+ message: () => string;
27
+ };
28
+ }>;
29
+
30
+ export { expect };
@@ -0,0 +1,34 @@
1
+ import { expect as expect$1 } from '@playwright/test';
2
+
3
+ // src/expect/matchers.ts
4
+ var expect = expect$1.extend({
5
+ /**
6
+ * Asserts the status of an `ApiResponse` from `apiClient.send()`, printing the body on
7
+ * failure — otherwise a wrong status tells you nothing about why.
8
+ */
9
+ toHaveStatus(received, expected) {
10
+ const pass = received.status === expected;
11
+ return {
12
+ pass,
13
+ name: "toHaveStatus",
14
+ expected,
15
+ actual: received.status,
16
+ message: () => pass ? `Expected status not to be ${expected}` : `Expected ${received.method} ${received.url} to return ${expected}, got ${received.status}
17
+ Body: ${JSON.stringify(received.data, null, 2)}`
18
+ };
19
+ },
20
+ /** Asserts a value matches a zod schema, listing the exact field-level issues on failure. */
21
+ toMatchSchema(received, schema) {
22
+ const result = schema.safeParse(received);
23
+ return {
24
+ pass: result.success,
25
+ name: "toMatchSchema",
26
+ message: () => result.success ? "Expected value not to match the schema" : `Value did not match the schema:
27
+ ${result.error.issues.map((issue) => ` - ${issue.path.join(".") || "(root)"}: ${issue.message}`).join("\n")}`
28
+ };
29
+ }
30
+ });
31
+
32
+ export { expect };
33
+ //# sourceMappingURL=index.js.map
34
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/expect/matchers.ts"],"names":["baseExpect"],"mappings":";;;AASO,IAAM,MAAA,GAASA,SAAW,MAAA,CAAO;AAAA;AAAA;AAAA;AAAA;AAAA,EAKtC,YAAA,CAAa,UAAgC,QAAA,EAAkB;AAC7D,IAAA,MAAM,IAAA,GAAO,SAAS,MAAA,KAAW,QAAA;AACjC,IAAA,OAAO;AAAA,MACL,IAAA;AAAA,MACA,IAAA,EAAM,cAAA;AAAA,MACN,QAAA;AAAA,MACA,QAAQ,QAAA,CAAS,MAAA;AAAA,MACjB,SAAS,MACP,IAAA,GACI,CAAA,0BAAA,EAA6B,QAAQ,KACrC,CAAA,SAAA,EAAY,QAAA,CAAS,MAAM,CAAA,CAAA,EAAI,SAAS,GAAG,CAAA,WAAA,EAAc,QAAQ,CAAA,MAAA,EAAS,SAAS,MAAM;AAAA,MAAA,EAChF,KAAK,SAAA,CAAU,QAAA,CAAS,IAAA,EAAM,IAAA,EAAM,CAAC,CAAC,CAAA;AAAA,KACvD;AAAA,EACF,CAAA;AAAA;AAAA,EAGA,aAAA,CAAc,UAAmB,MAAA,EAA0B;AACzD,IAAA,MAAM,MAAA,GAAS,MAAA,CAAO,SAAA,CAAU,QAAQ,CAAA;AACxC,IAAA,OAAO;AAAA,MACL,MAAM,MAAA,CAAO,OAAA;AAAA,MACb,IAAA,EAAM,eAAA;AAAA,MACN,OAAA,EAAS,MACP,MAAA,CAAO,OAAA,GACH,wCAAA,GACA,CAAA;AAAA,EAAoC,MAAA,CAAO,MAAM,MAAA,CAC9C,GAAA,CAAI,CAAC,KAAA,KAAU,CAAA,IAAA,EAAO,MAAM,IAAA,CAAK,IAAA,CAAK,GAAG,CAAA,IAAK,QAAQ,KAAK,KAAA,CAAM,OAAO,EAAE,CAAA,CAC1E,IAAA,CAAK,IAAI,CAAC,CAAA;AAAA,KACrB;AAAA,EACF;AACF,CAAC","file":"index.js","sourcesContent":["import { expect as baseExpect } from \"@playwright/test\";\nimport type { ZodType } from \"zod\";\nimport type { ApiResponse } from \"../api/types.js\";\n\n/**\n * `expect` with a few framework-specific matchers added. Projects get these automatically by\n * importing `expect` from `@emesoft_company/playwright-core/fixtures` (or their own `fixtures/index.ts`),\n * so there's nothing to register per project.\n */\nexport const expect = baseExpect.extend({\n /**\n * Asserts the status of an `ApiResponse` from `apiClient.send()`, printing the body on\n * failure — otherwise a wrong status tells you nothing about why.\n */\n toHaveStatus(received: ApiResponse<unknown>, expected: number) {\n const pass = received.status === expected;\n return {\n pass,\n name: \"toHaveStatus\",\n expected,\n actual: received.status,\n message: () =>\n pass\n ? `Expected status not to be ${expected}`\n : `Expected ${received.method} ${received.url} to return ${expected}, got ${received.status}\\n` +\n `Body: ${JSON.stringify(received.data, null, 2)}`,\n };\n },\n\n /** Asserts a value matches a zod schema, listing the exact field-level issues on failure. */\n toMatchSchema(received: unknown, schema: ZodType<unknown>) {\n const result = schema.safeParse(received);\n return {\n pass: result.success,\n name: \"toMatchSchema\",\n message: () =>\n result.success\n ? \"Expected value not to match the schema\"\n : `Value did not match the schema:\\n${result.error.issues\n .map((issue) => ` - ${issue.path.join(\".\") || \"(root)\"}: ${issue.message}`)\n .join(\"\\n\")}`,\n };\n },\n});\n"]}