@cronn/playwright-utils 0.0.1 → 0.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.
package/dist/index.d.mts CHANGED
@@ -1,5 +1,14 @@
1
1
  import { Normalizer } from "@cronn/playwright-file-snapshots";
2
2
  import { APIRequestContext, Locator, Page } from "@playwright/test";
3
+ //#region src/environment.d.ts
4
+ /**
5
+ * Whether the current process runs in a CI environment, based on the `CI`
6
+ * environment variable.
7
+ *
8
+ * Evaluated once when the module is loaded.
9
+ */
10
+ declare const isCI: boolean;
11
+ //#endregion
3
12
  //#region src/api/fetch-adapter.d.ts
4
13
  type FetchAPI = typeof fetch;
5
14
  /**
@@ -12,7 +21,22 @@ type FetchAPI = typeof fetch;
12
21
  * @param requestContext - Playwright request context to send requests with
13
22
  * @returns A function with the signature of the global `fetch`
14
23
  */
15
- declare function fetchAdapter(requestContext: APIRequestContext): FetchAPI;
24
+ declare function createFetchAdapter(requestContext: APIRequestContext): FetchAPI;
25
+ //#endregion
26
+ //#region src/file.d.ts
27
+ /**
28
+ * Resolves the given path segments against the root directory of the closest
29
+ * package, i.e. the closest directory containing a `package.json`, searching
30
+ * upwards from the current working directory.
31
+ *
32
+ * Useful for referencing files independently of the directory a test run is
33
+ * started from, e.g. a subdirectory of the package.
34
+ *
35
+ * @param paths - Path segments to resolve against the package root
36
+ * @returns The absolute path to the resolved location
37
+ * @throws If no package root can be found
38
+ */
39
+ declare function resolveFromPackageRoot(...paths: Array<string>): string;
16
40
  //#endregion
17
41
  //#region src/normalizers/mask-base-url.d.ts
18
42
  /**
@@ -46,5 +70,4 @@ declare function maskedValueWithIndex(name: string): (index: number) => string;
46
70
  */
47
71
  type PlaywrightTarget = Page | Locator;
48
72
  //#endregion
49
- export { type PlaywrightTarget, fetchAdapter, maskBaseURL, maskedValue, maskedValueWithIndex };
50
- //# sourceMappingURL=index.d.mts.map
73
+ export { type PlaywrightTarget, createFetchAdapter, isCI, maskBaseURL, maskedValue, maskedValueWithIndex, resolveFromPackageRoot };
package/dist/index.mjs CHANGED
@@ -1,4 +1,15 @@
1
+ import path from "node:path";
2
+ import { packageDirectorySync } from "package-directory";
1
3
  import { maskString, stringNormalizer } from "@cronn/playwright-file-snapshots";
4
+ //#region src/environment.ts
5
+ /**
6
+ * Whether the current process runs in a CI environment, based on the `CI`
7
+ * environment variable.
8
+ *
9
+ * Evaluated once when the module is loaded.
10
+ */
11
+ const isCI = process.env.CI === "true";
12
+ //#endregion
2
13
  //#region src/api/fetch-adapter.ts
3
14
  /**
4
15
  * Creates a `fetch`-compatible function backed by a Playwright
@@ -10,7 +21,7 @@ import { maskString, stringNormalizer } from "@cronn/playwright-file-snapshots";
10
21
  * @param requestContext - Playwright request context to send requests with
11
22
  * @returns A function with the signature of the global `fetch`
12
23
  */
13
- function fetchAdapter(requestContext) {
24
+ function createFetchAdapter(requestContext) {
14
25
  return async (input, init) => {
15
26
  const response = await requestContext.fetch(mapToUrl(input), await mapToOptions(input instanceof Request ? input : null, init));
16
27
  const responseBody = await response.body();
@@ -43,6 +54,25 @@ function mapToRequestBody(body) {
43
54
  return { data: body };
44
55
  }
45
56
  //#endregion
57
+ //#region src/file.ts
58
+ /**
59
+ * Resolves the given path segments against the root directory of the closest
60
+ * package, i.e. the closest directory containing a `package.json`, searching
61
+ * upwards from the current working directory.
62
+ *
63
+ * Useful for referencing files independently of the directory a test run is
64
+ * started from, e.g. a subdirectory of the package.
65
+ *
66
+ * @param paths - Path segments to resolve against the package root
67
+ * @returns The absolute path to the resolved location
68
+ * @throws If no package root can be found
69
+ */
70
+ function resolveFromPackageRoot(...paths) {
71
+ const packageDir = packageDirectorySync();
72
+ if (packageDir === void 0) throw new Error("Unable to resolve package directory");
73
+ return path.resolve(packageDir, ...paths);
74
+ }
75
+ //#endregion
46
76
  //#region src/normalizers/masked-value.ts
47
77
  /**
48
78
  * Formats a name as a masked placeholder, e.g. `maskedValue("base url")`
@@ -78,6 +108,4 @@ function identity(value) {
78
108
  return value;
79
109
  }
80
110
  //#endregion
81
- export { fetchAdapter, maskBaseURL, maskedValue, maskedValueWithIndex };
82
-
83
- //# sourceMappingURL=index.mjs.map
111
+ export { createFetchAdapter, isCI, maskBaseURL, maskedValue, maskedValueWithIndex, resolveFromPackageRoot };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cronn/playwright-utils",
3
- "version": "0.0.1",
3
+ "version": "0.1.0",
4
4
  "description": "Utilities for writing tests with Playwright",
5
5
  "keywords": [
6
6
  "playwright",
@@ -28,29 +28,8 @@
28
28
  "default": "./dist/index.mjs"
29
29
  }
30
30
  },
31
- "scripts": {
32
- "build": "tsdown",
33
- "clean": "rimraf .turbo dist coverage playwright-report test-results docs/.vitepress/cache docs/.vitepress/dist && pnpm run pnpm:clean",
34
- "compile": "tsc",
35
- "docs:build": "vitepress build docs",
36
- "docs:dev": "vitepress dev docs",
37
- "docs:preview": "vitepress preview docs",
38
- "format:check": "oxfmt --check",
39
- "format:fix": "oxfmt",
40
- "knip:check": "knip",
41
- "knip:fix": "knip --fix",
42
- "lint:check": "eslint . --max-warnings=0",
43
- "lint:fix": "eslint . --max-warnings=0 --fix",
44
- "playwright:install": "playwright install chromium",
45
- "pnpm:check": "pnpm dedupe --check",
46
- "pnpm:clean": "pnpm pm clean && pnpm store prune",
47
- "pnpm:fix": "pnpm dedupe",
48
- "prepublishOnly": "pnpm turbo run ci",
49
- "release": "pnpm turbo run build && pnpm changeset publish",
50
- "test:integration": "playwright test",
51
- "test:unit": "vitest run",
52
- "test:unit:coverage": "vitest run --coverage",
53
- "version": "pnpm changeset version && pnpm turbo run format:fix"
31
+ "dependencies": {
32
+ "package-directory": "8.2.0"
54
33
  },
55
34
  "devDependencies": {
56
35
  "@arethetypeswrong/core": "0.18.5",
@@ -75,7 +54,8 @@
75
54
  "typescript-eslint": "8.67.0",
76
55
  "vitepress": "2.0.0-alpha.19",
77
56
  "vitepress-plugin-group-icons": "1.7.6",
78
- "vitest": "4.1.10"
57
+ "vitest": "4.1.10",
58
+ "node": "runtime:24.19.0"
79
59
  },
80
60
  "peerDependencies": {
81
61
  "@cronn/playwright-file-snapshots": "^2",
@@ -85,15 +65,38 @@
85
65
  "packageManager": {
86
66
  "name": "pnpm",
87
67
  "version": "11.22.0",
88
- "onFail": "ignore"
68
+ "onFail": "download"
89
69
  },
90
70
  "runtime": {
91
71
  "name": "node",
92
72
  "version": "24.19.0",
93
- "onFail": "ignore"
73
+ "onFail": "download"
94
74
  }
95
75
  },
96
76
  "engines": {
97
77
  "node": "^22 || ^24 || >=26"
78
+ },
79
+ "scripts": {
80
+ "build": "tsdown",
81
+ "clean": "rimraf .turbo dist coverage playwright-report test-results docs/.vitepress/cache docs/.vitepress/dist && pnpm run pnpm:clean",
82
+ "compile": "tsc",
83
+ "docs:build": "vitepress build docs",
84
+ "docs:dev": "vitepress dev docs",
85
+ "docs:preview": "vitepress preview docs",
86
+ "format:check": "oxfmt --check",
87
+ "format:fix": "oxfmt",
88
+ "knip:check": "knip",
89
+ "knip:fix": "knip --fix",
90
+ "lint:check": "eslint . --max-warnings=0",
91
+ "lint:fix": "eslint . --max-warnings=0 --fix",
92
+ "playwright:install": "playwright install chromium",
93
+ "pnpm:check": "pnpm dedupe --check",
94
+ "pnpm:clean": "pnpm pm clean && pnpm store prune",
95
+ "pnpm:fix": "pnpm dedupe",
96
+ "release": "pnpm turbo run build && pnpm changeset publish",
97
+ "test:integration": "playwright test",
98
+ "test:unit": "vitest run",
99
+ "test:unit:coverage": "vitest run --coverage",
100
+ "version": "pnpm changeset version && pnpm turbo run format:fix"
98
101
  }
99
- }
102
+ }
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/api/fetch-adapter.ts","../src/normalizers/mask-base-url.ts","../src/normalizers/masked-value.ts","../src/types/playwright.ts"],"mappings":";;;KAEY,kBAAkB;;;;;;;;;;;iBAgBd,aAAa,gBAAgB,oBAAoB;;;;;;;;;iBCPjD,YAAY,QAC1B,8BACC,WAAW;;;;;;;;;iBCPE,YAAY;;;;;;;iBAWZ,qBAAqB,gBAAgB;;;;;;;KCXzC,mBAAmB,OAAO"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../src/api/fetch-adapter.ts","../src/normalizers/masked-value.ts","../src/normalizers/mask-base-url.ts"],"sourcesContent":["import type { APIRequestContext } from \"@playwright/test\";\n\nexport type FetchAPI = typeof fetch;\n\ntype PlaywrightFetchOptions = NonNullable<\n Parameters<APIRequestContext[\"fetch\"]>[1]\n>;\n\n/**\n * Creates a `fetch`-compatible function backed by a Playwright\n * {@link APIRequestContext}.\n *\n * Useful for passing Playwright's request context to API clients that expect\n * the standard Fetch API.\n *\n * @param requestContext - Playwright request context to send requests with\n * @returns A function with the signature of the global `fetch`\n */\nexport function fetchAdapter(requestContext: APIRequestContext): FetchAPI {\n return async (input, init): Promise<Response> => {\n const response = await requestContext.fetch(\n mapToUrl(input),\n await mapToOptions(input instanceof Request ? input : null, init),\n );\n\n const responseBody = await response.body();\n return new Response(Buffer.from(responseBody), {\n status: response.status(),\n headers: response.headers(),\n });\n };\n}\n\nfunction mapToUrl(input: RequestInfo | URL): string {\n if (typeof input === \"string\") {\n return input;\n }\n\n if (input instanceof Request) {\n return input.url;\n }\n\n return input.toString();\n}\n\nasync function mapToOptions(\n request: Request | null,\n init?: RequestInit,\n): Promise<PlaywrightFetchOptions> {\n const requestBody =\n request?.body !== null ? await request?.bytes() : undefined;\n return {\n method: request?.method ?? init?.method,\n headers: mapToRequestHeaders(request?.headers ?? init?.headers),\n ...mapToRequestBody(\n requestBody !== undefined ? Buffer.from(requestBody) : init?.body,\n ),\n };\n}\n\nfunction mapToRequestHeaders(\n headers: HeadersInit | undefined,\n): PlaywrightFetchOptions[\"headers\"] {\n if (Array.isArray(headers)) {\n return Object.fromEntries(headers);\n }\n\n if (headers instanceof Headers) {\n return Object.fromEntries(headers.entries());\n }\n\n return headers;\n}\n\nfunction mapToRequestBody(\n body: BodyInit | null | undefined,\n): Pick<PlaywrightFetchOptions, \"data\" | \"multipart\"> {\n if (body instanceof FormData) {\n return {\n multipart: body,\n };\n }\n\n return {\n data: body,\n };\n}\n","/**\n * Formats a name as a masked placeholder, e.g. `maskedValue(\"base url\")`\n * returns `[BASE_URL]`.\n *\n * @param name - Name of the masked value\n */\nexport function maskedValue(name: string): string {\n const normalizedName = name.toUpperCase().replace(/[ -.:,;]/g, \"_\");\n return `[${normalizedName}]`;\n}\n\n/**\n * Creates a factory for indexed masked placeholders, e.g. `[USER_1]`.\n *\n * @param name - Name of the masked value\n * @returns A function mapping an index to a masked placeholder\n */\nexport function maskedValueWithIndex(name: string): (index: number) => string {\n return (index: number) => maskedValue(`${name}_${index}`);\n}\n","import type { Normalizer } from \"@cronn/playwright-file-snapshots\";\nimport { maskString, stringNormalizer } from \"@cronn/playwright-file-snapshots\";\n\nimport { maskedValue } from \"./masked-value\";\n\n/**\n * Creates a normalizer that replaces occurrences of the base URL with\n * `[BASE_URL]`, keeping file snapshots stable across environments.\n *\n * @param baseURL - Base URL to mask; if `undefined`, values are left unchanged\n */\nexport function maskBaseURL<TValue>(\n baseURL: string | undefined,\n): Normalizer<TValue> {\n if (baseURL === undefined) {\n return identity<TValue>;\n }\n\n return stringNormalizer(maskString(baseURL, maskedValue(\"BASE_URL\")));\n}\n\nfunction identity<TValue>(value: TValue): TValue {\n return value;\n}\n"],"mappings":";;;;;;;;;;;;AAkBA,SAAgB,aAAa,gBAA6C;CACxE,OAAO,OAAO,OAAO,SAA4B;EAC/C,MAAM,WAAW,MAAM,eAAe,MACpC,SAAS,KAAK,GACd,MAAM,aAAa,iBAAiB,UAAU,QAAQ,MAAM,IAAI,CAClE;EAEA,MAAM,eAAe,MAAM,SAAS,KAAK;EACzC,OAAO,IAAI,SAAS,OAAO,KAAK,YAAY,GAAG;GAC7C,QAAQ,SAAS,OAAO;GACxB,SAAS,SAAS,QAAQ;EAC5B,CAAC;CACH;AACF;AAEA,SAAS,SAAS,OAAkC;CAClD,IAAI,OAAO,UAAU,UACnB,OAAO;CAGT,IAAI,iBAAiB,SACnB,OAAO,MAAM;CAGf,OAAO,MAAM,SAAS;AACxB;AAEA,eAAe,aACb,SACA,MACiC;CACjC,MAAM,cACJ,SAAS,SAAS,OAAO,MAAM,SAAS,MAAM,IAAI,KAAA;CACpD,OAAO;EACL,QAAQ,SAAS,UAAU,MAAM;EACjC,SAAS,oBAAoB,SAAS,WAAW,MAAM,OAAO;EAC9D,GAAG,iBACD,gBAAgB,KAAA,IAAY,OAAO,KAAK,WAAW,IAAI,MAAM,IAC/D;CACF;AACF;AAEA,SAAS,oBACP,SACmC;CACnC,IAAI,MAAM,QAAQ,OAAO,GACvB,OAAO,OAAO,YAAY,OAAO;CAGnC,IAAI,mBAAmB,SACrB,OAAO,OAAO,YAAY,QAAQ,QAAQ,CAAC;CAG7C,OAAO;AACT;AAEA,SAAS,iBACP,MACoD;CACpD,IAAI,gBAAgB,UAClB,OAAO,EACL,WAAW,KACb;CAGF,OAAO,EACL,MAAM,KACR;AACF;;;;;;;;;AChFA,SAAgB,YAAY,MAAsB;CAEhD,OAAO,IADgB,KAAK,YAAY,CAAC,CAAC,QAAQ,aAAa,GACvC,EAAE;AAC5B;;;;;;;AAQA,SAAgB,qBAAqB,MAAyC;CAC5E,QAAQ,UAAkB,YAAY,GAAG,KAAK,GAAG,OAAO;AAC1D;;;;;;;;;ACRA,SAAgB,YACd,SACoB;CACpB,IAAI,YAAY,KAAA,GACd,OAAO;CAGT,OAAO,iBAAiB,WAAW,SAAS,YAAY,UAAU,CAAC,CAAC;AACtE;AAEA,SAAS,SAAiB,OAAuB;CAC/C,OAAO;AACT"}