@cronn/playwright-utils 0.7.0 → 0.8.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 +59 -2
- package/dist/index.mjs +76 -2
- package/package.json +12 -14
package/dist/index.d.mts
CHANGED
|
@@ -606,7 +606,64 @@ export declare class RouteInterceptorFixture {
|
|
|
606
606
|
*/
|
|
607
607
|
export declare function resolveFromPackageRoot(...paths: Array<string>): string;
|
|
608
608
|
//#endregion
|
|
609
|
-
//#region src/page-object-model/
|
|
609
|
+
//#region src/page-object-model/form-filler.d.ts
|
|
610
|
+
interface Fillable<TValue> {
|
|
611
|
+
fill: Filler<TValue>;
|
|
612
|
+
}
|
|
613
|
+
type Filler<TValue> = (value: TValue) => Promise<void>;
|
|
614
|
+
type FormFields<TData> = { [K in keyof TData]-?: Fillable<Exclude<TData[K], undefined>> | Filler<Exclude<TData[K], undefined>>; };
|
|
615
|
+
/**
|
|
616
|
+
* Creates a filler function that fills a form declaratively from a data
|
|
617
|
+
* object, e.g. as the `fill` method of a page object.
|
|
618
|
+
*
|
|
619
|
+
* Each key of `fields` maps a key of the data to a form input: either an
|
|
620
|
+
* object with a `fill` method (such as a `Locator` or a nested page object) or
|
|
621
|
+
* a filler function receiving the value. Fields are filled one after another
|
|
622
|
+
* in the order of the keys in `fields`, and fields whose value is `undefined`
|
|
623
|
+
* are skipped.
|
|
624
|
+
*
|
|
625
|
+
* The type of the data is either given explicitly as type argument or inferred
|
|
626
|
+
* from `fields`. When inferred, filler functions need an explicit parameter
|
|
627
|
+
* type, otherwise their value is `unknown`. In both cases, the returned
|
|
628
|
+
* function accepts partial data.
|
|
629
|
+
*
|
|
630
|
+
* As the returned function is a filler itself, it can be used as a field of
|
|
631
|
+
* another form filler to fill nested data.
|
|
632
|
+
*
|
|
633
|
+
* @param fields - Mapping from each key of the data to the input to fill
|
|
634
|
+
* @returns A function filling the form with the given data
|
|
635
|
+
* @example
|
|
636
|
+
* ```ts
|
|
637
|
+
* const { checkbox, textbox } = roleLocators(page);
|
|
638
|
+
*
|
|
639
|
+
* const registrationForm = {
|
|
640
|
+
* fill: formFiller<Registration>({
|
|
641
|
+
* name: textbox("Name"),
|
|
642
|
+
* acceptTerms: (accepted) => checkbox("Accept terms").setChecked(accepted),
|
|
643
|
+
* }),
|
|
644
|
+
* };
|
|
645
|
+
* ```
|
|
646
|
+
*/
|
|
647
|
+
export declare function formFiller<TData extends object>(fields: FormFields<TData>): Filler<Partial<TData>>;
|
|
648
|
+
//#endregion
|
|
649
|
+
//#region src/page-object-model/extend-locator.d.ts
|
|
650
|
+
type WithoutLocatorKeys = Partial<Record<Exclude<keyof Locator, "toString">, never>>;
|
|
651
|
+
type ExtendedLocator<TExtensions extends WithoutLocatorKeys> = Locator & TExtensions;
|
|
652
|
+
/**
|
|
653
|
+
* Extends a `Locator` with custom properties and functions while retaining the full `Locator` API.
|
|
654
|
+
*
|
|
655
|
+
* Extensions must not override members of `Locator`. Locators derived from the extended locator
|
|
656
|
+
* (e.g. via `first()`, `filter()` or `locator()`) are plain `Locator`s without the extensions.
|
|
657
|
+
*
|
|
658
|
+
* Methods of `Locator` are bound to the original locator on every access, so accessing the same method
|
|
659
|
+
* twice returns different function instances (e.g. `extended.click !== extended.click`).
|
|
660
|
+
*
|
|
661
|
+
* @param locator The locator to extend
|
|
662
|
+
* @param createExtensions Creates the extensions, receiving the original locator
|
|
663
|
+
*/
|
|
664
|
+
export declare function extendLocator<TExtensions extends object & WithoutLocatorKeys>(locator: Locator, createExtensions: (locator: Locator) => TExtensions): ExtendedLocator<TExtensions>;
|
|
665
|
+
//#endregion
|
|
666
|
+
//#region src/page-object-model/role-locators.d.ts
|
|
610
667
|
type RoleLocators = Record<Role, RoleLocator>;
|
|
611
668
|
interface RoleLocator {
|
|
612
669
|
(options?: RoleLocatorOptions): Locator;
|
|
@@ -673,4 +730,4 @@ export declare function maskedValueWithIndex(name: string): (index: number) => s
|
|
|
673
730
|
*/
|
|
674
731
|
type PlaywrightTarget = Page | Locator;
|
|
675
732
|
//#endregion
|
|
676
|
-
export type { ConsoleMessageFilter, ConsoleMessageLevel, CspFixtures, CspViolation, HttpMethod, PlaywrightTarget, ResponseHandler, RoleLocators, RouteFilter };
|
|
733
|
+
export type { ConsoleMessageFilter, ConsoleMessageLevel, CspFixtures, CspViolation, ExtendedLocator, FormFields, HttpMethod, PlaywrightTarget, ResponseHandler, RoleLocators, RouteFilter };
|
package/dist/index.mjs
CHANGED
|
@@ -789,7 +789,81 @@ function resolveFromPackageRoot(...paths) {
|
|
|
789
789
|
return path.resolve(packageDir, ...paths);
|
|
790
790
|
}
|
|
791
791
|
//#endregion
|
|
792
|
-
//#region src/page-object-model/
|
|
792
|
+
//#region src/page-object-model/form-filler.ts
|
|
793
|
+
/**
|
|
794
|
+
* Creates a filler function that fills a form declaratively from a data
|
|
795
|
+
* object, e.g. as the `fill` method of a page object.
|
|
796
|
+
*
|
|
797
|
+
* Each key of `fields` maps a key of the data to a form input: either an
|
|
798
|
+
* object with a `fill` method (such as a `Locator` or a nested page object) or
|
|
799
|
+
* a filler function receiving the value. Fields are filled one after another
|
|
800
|
+
* in the order of the keys in `fields`, and fields whose value is `undefined`
|
|
801
|
+
* are skipped.
|
|
802
|
+
*
|
|
803
|
+
* The type of the data is either given explicitly as type argument or inferred
|
|
804
|
+
* from `fields`. When inferred, filler functions need an explicit parameter
|
|
805
|
+
* type, otherwise their value is `unknown`. In both cases, the returned
|
|
806
|
+
* function accepts partial data.
|
|
807
|
+
*
|
|
808
|
+
* As the returned function is a filler itself, it can be used as a field of
|
|
809
|
+
* another form filler to fill nested data.
|
|
810
|
+
*
|
|
811
|
+
* @param fields - Mapping from each key of the data to the input to fill
|
|
812
|
+
* @returns A function filling the form with the given data
|
|
813
|
+
* @example
|
|
814
|
+
* ```ts
|
|
815
|
+
* const { checkbox, textbox } = roleLocators(page);
|
|
816
|
+
*
|
|
817
|
+
* const registrationForm = {
|
|
818
|
+
* fill: formFiller<Registration>({
|
|
819
|
+
* name: textbox("Name"),
|
|
820
|
+
* acceptTerms: (accepted) => checkbox("Accept terms").setChecked(accepted),
|
|
821
|
+
* }),
|
|
822
|
+
* };
|
|
823
|
+
* ```
|
|
824
|
+
*/
|
|
825
|
+
function formFiller(fields) {
|
|
826
|
+
return async (data) => {
|
|
827
|
+
for (const [key, filler] of Object.entries(fields)) {
|
|
828
|
+
const value = data[key];
|
|
829
|
+
if (value === void 0) continue;
|
|
830
|
+
if (typeof filler === "function") await filler(value);
|
|
831
|
+
else await filler.fill(value);
|
|
832
|
+
}
|
|
833
|
+
};
|
|
834
|
+
}
|
|
835
|
+
//#endregion
|
|
836
|
+
//#region src/page-object-model/extend-locator.ts
|
|
837
|
+
/**
|
|
838
|
+
* Extends a `Locator` with custom properties and functions while retaining the full `Locator` API.
|
|
839
|
+
*
|
|
840
|
+
* Extensions must not override members of `Locator`. Locators derived from the extended locator
|
|
841
|
+
* (e.g. via `first()`, `filter()` or `locator()`) are plain `Locator`s without the extensions.
|
|
842
|
+
*
|
|
843
|
+
* Methods of `Locator` are bound to the original locator on every access, so accessing the same method
|
|
844
|
+
* twice returns different function instances (e.g. `extended.click !== extended.click`).
|
|
845
|
+
*
|
|
846
|
+
* @param locator The locator to extend
|
|
847
|
+
* @param createExtensions Creates the extensions, receiving the original locator
|
|
848
|
+
*/
|
|
849
|
+
function extendLocator(locator, createExtensions) {
|
|
850
|
+
const extensions = createExtensions(locator);
|
|
851
|
+
return new Proxy(locator, {
|
|
852
|
+
get(target, property) {
|
|
853
|
+
if (isOwnKeyOf(extensions, property)) return extensions[property];
|
|
854
|
+
const value = Reflect.get(target, property, target);
|
|
855
|
+
return typeof value === "function" && property !== "constructor" ? value.bind(target) : value;
|
|
856
|
+
},
|
|
857
|
+
has(target, property) {
|
|
858
|
+
return isOwnKeyOf(extensions, property) || Reflect.has(target, property);
|
|
859
|
+
}
|
|
860
|
+
});
|
|
861
|
+
}
|
|
862
|
+
function isOwnKeyOf(object, key) {
|
|
863
|
+
return Object.hasOwn(object, key);
|
|
864
|
+
}
|
|
865
|
+
//#endregion
|
|
866
|
+
//#region src/page-object-model/role-locators.ts
|
|
793
867
|
const ROLES = [
|
|
794
868
|
"alert",
|
|
795
869
|
"alertdialog",
|
|
@@ -951,4 +1025,4 @@ function identity(value) {
|
|
|
951
1025
|
return value;
|
|
952
1026
|
}
|
|
953
1027
|
//#endregion
|
|
954
|
-
export { ConsoleCaptor, CspCaptor, RouteInterceptor, RouteInterceptorFixture, captureConsole, captureCspViolations, createFetchAdapter, cspFixtures, hasLogLevel, interceptRoute, isCI, maskBaseURL, maskedValue, maskedValueWithIndex, matchPath, modifyJsonBody, modifyTextBody, resolveFromPackageRoot, roleLocators };
|
|
1028
|
+
export { ConsoleCaptor, CspCaptor, RouteInterceptor, RouteInterceptorFixture, captureConsole, captureCspViolations, createFetchAdapter, cspFixtures, extendLocator, formFiller, hasLogLevel, interceptRoute, isCI, maskBaseURL, maskedValue, maskedValueWithIndex, matchPath, modifyJsonBody, modifyTextBody, resolveFromPackageRoot, roleLocators };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cronn/playwright-utils",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "Utilities for writing tests with Playwright",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"playwright",
|
|
@@ -33,29 +33,29 @@
|
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
35
|
"@arethetypeswrong/core": "0.18.5",
|
|
36
|
-
"@changesets/cli": "3.0.
|
|
36
|
+
"@changesets/cli": "3.0.3",
|
|
37
37
|
"@cronn/element-snapshot": "0.30.0",
|
|
38
38
|
"@cronn/playwright-file-snapshots": "2.2.2",
|
|
39
39
|
"@playwright/test": "1.63.0",
|
|
40
|
-
"@types/node": "24.
|
|
40
|
+
"@types/node": "24.19.0",
|
|
41
41
|
"@typescript/native": "npm:typescript@^7.0.2",
|
|
42
|
-
"@vitest/coverage-v8": "5.0.
|
|
43
|
-
"eslint": "10.
|
|
42
|
+
"@vitest/coverage-v8": "5.0.2",
|
|
43
|
+
"eslint": "10.11.0",
|
|
44
44
|
"eslint-config-prettier": "10.1.8",
|
|
45
45
|
"eslint-plugin-check-file": "3.3.2",
|
|
46
46
|
"eslint-plugin-unused-imports": "4.4.1",
|
|
47
|
-
"knip": "6.
|
|
48
|
-
"oxc-minify": "0.
|
|
49
|
-
"oxfmt": "0.
|
|
47
|
+
"knip": "6.38.0",
|
|
48
|
+
"oxc-minify": "0.151.0",
|
|
49
|
+
"oxfmt": "0.70.0",
|
|
50
50
|
"publint": "0.3.24",
|
|
51
51
|
"rimraf": "6.1.3",
|
|
52
52
|
"tsdown": "0.23.0",
|
|
53
|
-
"turbo": "2.
|
|
53
|
+
"turbo": "2.11.5",
|
|
54
54
|
"typescript": "npm:@typescript/typescript6@^6.0.2",
|
|
55
|
-
"typescript-eslint": "8.70.
|
|
55
|
+
"typescript-eslint": "8.70.1",
|
|
56
56
|
"vitepress": "2.0.0-alpha.20",
|
|
57
57
|
"vitepress-plugin-group-icons": "1.7.6",
|
|
58
|
-
"vitest": "5.0.
|
|
58
|
+
"vitest": "5.0.2"
|
|
59
59
|
},
|
|
60
60
|
"peerDependencies": {
|
|
61
61
|
"@cronn/playwright-file-snapshots": "^2",
|
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
"devEngines": {
|
|
65
65
|
"packageManager": {
|
|
66
66
|
"name": "pnpm",
|
|
67
|
-
"version": "12.
|
|
67
|
+
"version": "12.9.1",
|
|
68
68
|
"onFail": "download"
|
|
69
69
|
},
|
|
70
70
|
"runtime": {
|
|
@@ -90,9 +90,7 @@
|
|
|
90
90
|
"lint:check": "eslint . --max-warnings=0",
|
|
91
91
|
"lint:fix": "eslint . --max-warnings=0 --fix",
|
|
92
92
|
"playwright:install": "playwright install chromium",
|
|
93
|
-
"pnpm:check": "pnpm dedupe --check",
|
|
94
93
|
"pnpm:clean": "pnpm pm clean && pnpm store prune",
|
|
95
|
-
"pnpm:fix": "pnpm dedupe",
|
|
96
94
|
"release": "pnpm turbo run build && pnpm changeset publish",
|
|
97
95
|
"test:integration": "playwright test",
|
|
98
96
|
"test:unit": "vitest run",
|