@redrockswebdevelopment/formstack-form-testing 0.1.27 → 0.1.28
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.ts +51 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +177 -14
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -978,6 +978,19 @@ export function buildLiveFormProductValue(value, current = {}) {
|
|
|
978
978
|
export function buildLiveFormRatingValue(value) {
|
|
979
979
|
return { value: String(value) };
|
|
980
980
|
}
|
|
981
|
+
export function readLiveFormRatingValue(value) {
|
|
982
|
+
if (typeof value === "string" || typeof value === "number")
|
|
983
|
+
return String(value);
|
|
984
|
+
if (!value || typeof value !== "object")
|
|
985
|
+
return null;
|
|
986
|
+
const selected = value.value;
|
|
987
|
+
return typeof selected === "string" || typeof selected === "number" ? String(selected) : null;
|
|
988
|
+
}
|
|
989
|
+
export function normalizeLiveFormRatingValue(value) {
|
|
990
|
+
if (typeof value === "string" || typeof value === "number")
|
|
991
|
+
return buildLiveFormRatingValue(value);
|
|
992
|
+
return buildLiveFormRatingValue(value.value);
|
|
993
|
+
}
|
|
981
994
|
export function buildLiveFormMatrixValue(selections) {
|
|
982
995
|
return {
|
|
983
996
|
value: selections.map((selection) => {
|
|
@@ -2077,6 +2090,88 @@ export async function waitForLiveFormMatrixState(page, options) {
|
|
|
2077
2090
|
}
|
|
2078
2091
|
return latest;
|
|
2079
2092
|
}
|
|
2093
|
+
export async function readLiveFormRatingState(page, options) {
|
|
2094
|
+
if (!hasEvaluate(page)) {
|
|
2095
|
+
throw new Error("readLiveFormRatingState requires a Playwright page with evaluate().");
|
|
2096
|
+
}
|
|
2097
|
+
return page.evaluate((stateOptions) => {
|
|
2098
|
+
const normalizeText = (value) => (value ?? "").replace(/\s+/g, " ").trim();
|
|
2099
|
+
const root = stateOptions.selector != null
|
|
2100
|
+
? document.querySelector(stateOptions.selector)
|
|
2101
|
+
: stateOptions.internalLabel != null
|
|
2102
|
+
? document.querySelector(`[data-internal-label="${CSS.escape(stateOptions.internalLabel)}"]`)
|
|
2103
|
+
: stateOptions.fieldId == null
|
|
2104
|
+
? null
|
|
2105
|
+
: document.querySelector(`#fsCell${CSS.escape(String(stateOptions.fieldId))}, #fsFieldCell${CSS.escape(String(stateOptions.fieldId))}, [data-testid="field-${CSS.escape(String(stateOptions.fieldId))}"]`);
|
|
2106
|
+
const candidates = root
|
|
2107
|
+
? Array.from(root.querySelectorAll("input, button, [role=\"radio\"], [role=\"button\"], [aria-checked], [aria-pressed], [aria-selected], [data-value], [data-rating], [data-score]"))
|
|
2108
|
+
: [];
|
|
2109
|
+
const controlValue = (element) => {
|
|
2110
|
+
const htmlInput = element instanceof HTMLInputElement ? element.value : "";
|
|
2111
|
+
const text = normalizeText(element.textContent);
|
|
2112
|
+
return element.getAttribute("value") ??
|
|
2113
|
+
(htmlInput.length > 0 ? htmlInput : null) ??
|
|
2114
|
+
element.getAttribute("data-value") ??
|
|
2115
|
+
element.getAttribute("data-rating") ??
|
|
2116
|
+
element.getAttribute("data-score") ??
|
|
2117
|
+
element.getAttribute("aria-label")?.match(/\d+(?:\.\d+)?/)?.[0] ??
|
|
2118
|
+
(text.length > 0 ? text : null);
|
|
2119
|
+
};
|
|
2120
|
+
const isSelected = (element) => {
|
|
2121
|
+
const checked = element instanceof HTMLInputElement ? element.checked : null;
|
|
2122
|
+
const ariaChecked = element.getAttribute("aria-checked");
|
|
2123
|
+
const ariaPressed = element.getAttribute("aria-pressed");
|
|
2124
|
+
const ariaSelected = element.getAttribute("aria-selected");
|
|
2125
|
+
const classes = Array.from(element.classList).join(" ");
|
|
2126
|
+
return checked === true ||
|
|
2127
|
+
ariaChecked === "true" ||
|
|
2128
|
+
ariaPressed === "true" ||
|
|
2129
|
+
ariaSelected === "true" ||
|
|
2130
|
+
/\b(active|checked|selected|filled|on)\b/i.test(classes);
|
|
2131
|
+
};
|
|
2132
|
+
const controls = candidates
|
|
2133
|
+
.map((element) => ({
|
|
2134
|
+
tagName: element.tagName.toLowerCase(),
|
|
2135
|
+
id: element.getAttribute("id"),
|
|
2136
|
+
value: controlValue(element),
|
|
2137
|
+
text: normalizeText(element.textContent),
|
|
2138
|
+
ariaChecked: element.getAttribute("aria-checked"),
|
|
2139
|
+
ariaPressed: element.getAttribute("aria-pressed"),
|
|
2140
|
+
ariaSelected: element.getAttribute("aria-selected"),
|
|
2141
|
+
checked: element instanceof HTMLInputElement ? element.checked : null,
|
|
2142
|
+
selected: isSelected(element),
|
|
2143
|
+
}))
|
|
2144
|
+
.filter((control) => control.value !== null && control.value.length > 0);
|
|
2145
|
+
const selectedControls = controls.filter((control) => control.selected);
|
|
2146
|
+
const selectedValue = selectedControls.length > 0
|
|
2147
|
+
? selectedControls[selectedControls.length - 1]?.value ?? null
|
|
2148
|
+
: null;
|
|
2149
|
+
const allValues = controls
|
|
2150
|
+
.map((control) => control.value)
|
|
2151
|
+
.filter((value) => typeof value === "string" && value.length > 0);
|
|
2152
|
+
return {
|
|
2153
|
+
fieldMatched: Boolean(root),
|
|
2154
|
+
selectedValue,
|
|
2155
|
+
allValues,
|
|
2156
|
+
...(stateOptions.expectedValue === undefined ? {} : { expectedValue: stateOptions.expectedValue }),
|
|
2157
|
+
matched: Boolean(root) &&
|
|
2158
|
+
selectedValue !== null &&
|
|
2159
|
+
(stateOptions.expectedValue === undefined || selectedValue === stateOptions.expectedValue),
|
|
2160
|
+
controls,
|
|
2161
|
+
};
|
|
2162
|
+
}, options);
|
|
2163
|
+
}
|
|
2164
|
+
export async function waitForLiveFormRatingState(page, options) {
|
|
2165
|
+
const timeoutMs = options.timeoutMs ?? 10_000;
|
|
2166
|
+
const intervalMs = options.intervalMs ?? 100;
|
|
2167
|
+
const startedAt = Date.now();
|
|
2168
|
+
let latest = await readLiveFormRatingState(page, options);
|
|
2169
|
+
while (!latest.matched && Date.now() - startedAt < timeoutMs) {
|
|
2170
|
+
await delay(intervalMs);
|
|
2171
|
+
latest = await readLiveFormRatingState(page, options);
|
|
2172
|
+
}
|
|
2173
|
+
return latest;
|
|
2174
|
+
}
|
|
2080
2175
|
export async function dispatchLiveFormFieldDomEvents(page, options) {
|
|
2081
2176
|
if (!hasEvaluate(page)) {
|
|
2082
2177
|
throw new Error("dispatchLiveFormFieldDomEvents requires a Playwright page with evaluate().");
|
|
@@ -3797,6 +3892,49 @@ export async function setLiveFormMatrixValues(page, options) {
|
|
|
3797
3892
|
(visibility?.matched ?? true),
|
|
3798
3893
|
};
|
|
3799
3894
|
}
|
|
3895
|
+
export async function setLiveFormRatingValue(page, options) {
|
|
3896
|
+
const payload = normalizeLiveFormRatingValue(options.value);
|
|
3897
|
+
const value = payload.value;
|
|
3898
|
+
const transaction = await performLiveFormFieldTransaction(page, {
|
|
3899
|
+
write: {
|
|
3900
|
+
...(options.write ?? {}),
|
|
3901
|
+
target: options.target,
|
|
3902
|
+
value: payload,
|
|
3903
|
+
notify: options.write?.notify ?? true,
|
|
3904
|
+
},
|
|
3905
|
+
fieldKind: "rating",
|
|
3906
|
+
waitForEvent: options.waitForEvent ?? true,
|
|
3907
|
+
dispatchDomEvents: options.dispatchDomEvents ?? "auto",
|
|
3908
|
+
afterQuiet: options.afterQuiet ?? { quietMs: 200, timeoutMs: 5_000 },
|
|
3909
|
+
...(options.afterValidation === undefined ? {} : { afterValidation: options.afterValidation }),
|
|
3910
|
+
});
|
|
3911
|
+
const dom = await waitForLiveFormRatingState(page, {
|
|
3912
|
+
...options.target,
|
|
3913
|
+
expectedValue: value,
|
|
3914
|
+
...(options.write?.timeoutMs === undefined ? {} : { timeoutMs: options.write.timeoutMs }),
|
|
3915
|
+
});
|
|
3916
|
+
const visibilityTargets = [
|
|
3917
|
+
...(options.expectVisible ?? []).map((target) => ({ ...target, visible: true })),
|
|
3918
|
+
...(options.expectHidden ?? []).map((target) => ({ ...target, visible: false })),
|
|
3919
|
+
];
|
|
3920
|
+
const visibility = visibilityTargets.length > 0
|
|
3921
|
+
? await waitForLiveFormVisibility(page, { targets: visibilityTargets })
|
|
3922
|
+
: undefined;
|
|
3923
|
+
return {
|
|
3924
|
+
payload,
|
|
3925
|
+
value,
|
|
3926
|
+
transaction,
|
|
3927
|
+
dom,
|
|
3928
|
+
...(visibility ? { visibility } : {}),
|
|
3929
|
+
ok: transaction.write.valueMatched &&
|
|
3930
|
+
(transaction.event?.matched ?? true) &&
|
|
3931
|
+
(transaction.domDispatch ? transaction.domDispatch.matchedControlCount >= 1 : true) &&
|
|
3932
|
+
(transaction.quiet?.quiet ?? true) &&
|
|
3933
|
+
((transaction.validation?.inlineErrors.length ?? 0) === 0) &&
|
|
3934
|
+
dom.matched &&
|
|
3935
|
+
(visibility?.matched ?? true),
|
|
3936
|
+
};
|
|
3937
|
+
}
|
|
3800
3938
|
export async function answerProgressiveLiveFormField(page, options) {
|
|
3801
3939
|
const validationOptions = options.afterValidation === undefined ? undefined : typeof options.afterValidation === "object" ? options.afterValidation : {};
|
|
3802
3940
|
const checkboxTransaction = options.fieldKind === "checkbox"
|
|
@@ -3843,6 +3981,17 @@ export async function answerProgressiveLiveFormField(page, options) {
|
|
|
3843
3981
|
...(validationOptions ? { afterValidation: validationOptions } : {}),
|
|
3844
3982
|
})
|
|
3845
3983
|
: undefined;
|
|
3984
|
+
const ratingTransaction = !checkboxTransaction && !choiceTransaction && !selectTransaction && !matrixTransaction && options.fieldKind === "rating"
|
|
3985
|
+
? await setLiveFormRatingValue(page, {
|
|
3986
|
+
target: options.target,
|
|
3987
|
+
value: options.value,
|
|
3988
|
+
...(options.write === undefined ? {} : { write: options.write }),
|
|
3989
|
+
waitForEvent: options.waitForEvent ?? true,
|
|
3990
|
+
dispatchDomEvents: options.dispatchDomEvents ?? "auto",
|
|
3991
|
+
afterQuiet: options.afterQuiet ?? true,
|
|
3992
|
+
...(validationOptions ? { afterValidation: validationOptions } : {}),
|
|
3993
|
+
})
|
|
3994
|
+
: undefined;
|
|
3846
3995
|
const transaction = checkboxTransaction
|
|
3847
3996
|
? checkboxTransaction.transaction
|
|
3848
3997
|
: choiceTransaction
|
|
@@ -3851,19 +4000,21 @@ export async function answerProgressiveLiveFormField(page, options) {
|
|
|
3851
4000
|
? selectTransaction.transaction
|
|
3852
4001
|
: matrixTransaction
|
|
3853
4002
|
? matrixTransaction.transaction
|
|
3854
|
-
:
|
|
3855
|
-
|
|
3856
|
-
|
|
3857
|
-
|
|
3858
|
-
|
|
3859
|
-
|
|
3860
|
-
|
|
3861
|
-
|
|
3862
|
-
|
|
3863
|
-
|
|
3864
|
-
|
|
3865
|
-
|
|
3866
|
-
|
|
4003
|
+
: ratingTransaction
|
|
4004
|
+
? ratingTransaction.transaction
|
|
4005
|
+
: await performLiveFormFieldTransaction(page, {
|
|
4006
|
+
write: {
|
|
4007
|
+
...(options.write ?? {}),
|
|
4008
|
+
target: options.target,
|
|
4009
|
+
value: options.value,
|
|
4010
|
+
notify: options.write?.notify ?? true,
|
|
4011
|
+
},
|
|
4012
|
+
...(options.fieldKind ? { fieldKind: options.fieldKind } : {}),
|
|
4013
|
+
waitForEvent: options.waitForEvent ?? true,
|
|
4014
|
+
dispatchDomEvents: options.dispatchDomEvents ?? "auto",
|
|
4015
|
+
afterQuiet: options.afterQuiet ?? true,
|
|
4016
|
+
...(validationOptions ? { afterValidation: validationOptions } : {}),
|
|
4017
|
+
});
|
|
3867
4018
|
const visibilityTargets = [
|
|
3868
4019
|
...(options.expectVisible ?? []),
|
|
3869
4020
|
...(options.expectHidden ?? []).map((target) => ({ ...target, visible: false })),
|
|
@@ -5338,7 +5489,19 @@ export const liveFormFieldRecipes = {
|
|
|
5338
5489
|
});
|
|
5339
5490
|
},
|
|
5340
5491
|
}),
|
|
5341
|
-
setRatingApi: (name, internalLabel, value, options) =>
|
|
5492
|
+
setRatingApi: (name, internalLabel, value, options = {}) => ({
|
|
5493
|
+
name,
|
|
5494
|
+
run: async (harness) => {
|
|
5495
|
+
await setLiveFormRatingValue(harness.page, {
|
|
5496
|
+
target: { internalLabel },
|
|
5497
|
+
value,
|
|
5498
|
+
write: { notify: options.notify ?? true },
|
|
5499
|
+
waitForEvent: options.waitForEvent ?? (options.notify ?? true),
|
|
5500
|
+
dispatchDomEvents: options.dispatchDomEvents ?? "auto",
|
|
5501
|
+
afterQuiet: options.waitForQuiet ?? true,
|
|
5502
|
+
});
|
|
5503
|
+
},
|
|
5504
|
+
}),
|
|
5342
5505
|
setProductApi: (name, internalLabel, value, options) => apiRecipeStep(name, { internalLabel }, buildLiveFormProductValue(value), options),
|
|
5343
5506
|
setFieldApiAuto: (name, internalLabel, value, fieldKind, options = {}) => apiRecipeStep(name, { internalLabel }, value, { ...options, fieldKind, dispatchDomEvents: "auto" }),
|
|
5344
5507
|
setNameApiAndDispatch: (name, internalLabel, value, options = {}) => liveFormFieldRecipes.setNameApi(name, internalLabel, value, { ...options, fieldKind: options.fieldKind ?? "name", dispatchDomEvents: "auto" }),
|