@redrockswebdevelopment/formstack-form-testing 0.1.26 → 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 +182 -15
- 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) => {
|
|
@@ -2028,7 +2041,11 @@ export async function readLiveFormMatrixState(page, options) {
|
|
|
2028
2041
|
normalizeText(label?.textContent) ||
|
|
2029
2042
|
normalizeText(control.value) ||
|
|
2030
2043
|
null;
|
|
2031
|
-
const selection = row && column
|
|
2044
|
+
const selection = row && column
|
|
2045
|
+
? `${row} = ${column}`
|
|
2046
|
+
: control.value.length > 0
|
|
2047
|
+
? control.value
|
|
2048
|
+
: null;
|
|
2032
2049
|
return {
|
|
2033
2050
|
row,
|
|
2034
2051
|
column,
|
|
@@ -2073,6 +2090,88 @@ export async function waitForLiveFormMatrixState(page, options) {
|
|
|
2073
2090
|
}
|
|
2074
2091
|
return latest;
|
|
2075
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
|
+
}
|
|
2076
2175
|
export async function dispatchLiveFormFieldDomEvents(page, options) {
|
|
2077
2176
|
if (!hasEvaluate(page)) {
|
|
2078
2177
|
throw new Error("dispatchLiveFormFieldDomEvents requires a Playwright page with evaluate().");
|
|
@@ -3793,6 +3892,49 @@ export async function setLiveFormMatrixValues(page, options) {
|
|
|
3793
3892
|
(visibility?.matched ?? true),
|
|
3794
3893
|
};
|
|
3795
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
|
+
}
|
|
3796
3938
|
export async function answerProgressiveLiveFormField(page, options) {
|
|
3797
3939
|
const validationOptions = options.afterValidation === undefined ? undefined : typeof options.afterValidation === "object" ? options.afterValidation : {};
|
|
3798
3940
|
const checkboxTransaction = options.fieldKind === "checkbox"
|
|
@@ -3839,6 +3981,17 @@ export async function answerProgressiveLiveFormField(page, options) {
|
|
|
3839
3981
|
...(validationOptions ? { afterValidation: validationOptions } : {}),
|
|
3840
3982
|
})
|
|
3841
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;
|
|
3842
3995
|
const transaction = checkboxTransaction
|
|
3843
3996
|
? checkboxTransaction.transaction
|
|
3844
3997
|
: choiceTransaction
|
|
@@ -3847,19 +4000,21 @@ export async function answerProgressiveLiveFormField(page, options) {
|
|
|
3847
4000
|
? selectTransaction.transaction
|
|
3848
4001
|
: matrixTransaction
|
|
3849
4002
|
? matrixTransaction.transaction
|
|
3850
|
-
:
|
|
3851
|
-
|
|
3852
|
-
|
|
3853
|
-
|
|
3854
|
-
|
|
3855
|
-
|
|
3856
|
-
|
|
3857
|
-
|
|
3858
|
-
|
|
3859
|
-
|
|
3860
|
-
|
|
3861
|
-
|
|
3862
|
-
|
|
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
|
+
});
|
|
3863
4018
|
const visibilityTargets = [
|
|
3864
4019
|
...(options.expectVisible ?? []),
|
|
3865
4020
|
...(options.expectHidden ?? []).map((target) => ({ ...target, visible: false })),
|
|
@@ -5334,7 +5489,19 @@ export const liveFormFieldRecipes = {
|
|
|
5334
5489
|
});
|
|
5335
5490
|
},
|
|
5336
5491
|
}),
|
|
5337
|
-
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
|
+
}),
|
|
5338
5505
|
setProductApi: (name, internalLabel, value, options) => apiRecipeStep(name, { internalLabel }, buildLiveFormProductValue(value), options),
|
|
5339
5506
|
setFieldApiAuto: (name, internalLabel, value, fieldKind, options = {}) => apiRecipeStep(name, { internalLabel }, value, { ...options, fieldKind, dispatchDomEvents: "auto" }),
|
|
5340
5507
|
setNameApiAndDispatch: (name, internalLabel, value, options = {}) => liveFormFieldRecipes.setNameApi(name, internalLabel, value, { ...options, fieldKind: options.fieldKind ?? "name", dispatchDomEvents: "auto" }),
|