@suffolklitlab/alkiln 5.9.0 → 5.10.0-fix-typing1
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/.github/workflows/github_server.yml +1 -1
- package/.github/workflows/playground.yml +6 -1
- package/CHANGELOG.md +24 -1
- package/lib/cucumber_8_shim.js +1 -0
- package/lib/scope.js +67 -19
- package/lib/steps.js +21 -2
- package/lib/utils/session_vars.js +1 -1
- package/package.json +1 -1
- package/tests/unit_tests/fields.fixtures.js +70 -0
- package/tests/unit_tests/getAllFields.test.js +8 -2
- package/tests/unit_tests/html.fixtures.js +56 -1
|
@@ -91,5 +91,5 @@ jobs:
|
|
|
91
91
|
#### to debug the docker install step
|
|
92
92
|
#### Use a "tag expression" to specify which tagged tests to run (https://cucumber.io/docs/cucumber/api/#tag-expressions)
|
|
93
93
|
# ALKILN_TAG_EXPRESSION: @a_tag_expression
|
|
94
|
-
|
|
94
|
+
ALKILN_VERSION: url
|
|
95
95
|
|
|
@@ -44,6 +44,11 @@ jobs:
|
|
|
44
44
|
# relative paths to action files
|
|
45
45
|
- uses: actions/checkout@v3
|
|
46
46
|
|
|
47
|
+
- name: Pause between triggers
|
|
48
|
+
if: (github.event_name == 'pull_request' && ! github.event.pull_request.head.repo.fork)
|
|
49
|
+
shell: bash
|
|
50
|
+
run: sleep 30
|
|
51
|
+
|
|
47
52
|
#### Developer note: you'll need to replace `.` with the path to
|
|
48
53
|
#### the repo and branch and leave off the trailing `/`
|
|
49
54
|
#### For example suffolkLITLab/ALKiln@v5
|
|
@@ -55,4 +60,4 @@ jobs:
|
|
|
55
60
|
#### to debug the docker install step
|
|
56
61
|
# ALKILN_TAG_EXPRESSION: @a_tag_expression
|
|
57
62
|
#### Developer note: you probalby don't need this
|
|
58
|
-
|
|
63
|
+
ALKILN_VERSION: url
|
package/CHANGELOG.md
CHANGED
|
@@ -43,7 +43,30 @@ Format:
|
|
|
43
43
|
-
|
|
44
44
|
-->
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
## [Unreleased]
|
|
47
|
+
|
|
48
|
+
### Fixed
|
|
49
|
+
|
|
50
|
+
- Fixes the issue that typing is too fast for some fields, like Ajax comboboxes. See [#857](https://github.com/SuffolkLITLab/ALKiln/issues/857).
|
|
51
|
+
|
|
52
|
+
## [5.10.0] - 2024-02-22
|
|
53
|
+
|
|
54
|
+
### Added
|
|
55
|
+
|
|
56
|
+
- New Step: 'I go to ""' to go to any arbitrary url, not just arbitrary interview urls.
|
|
57
|
+
- New navigation report messages.
|
|
58
|
+
- Allow non-local environments to get debug logs. For example, the GitHub console during a workflow run.
|
|
59
|
+
|
|
60
|
+
### Changed
|
|
61
|
+
|
|
62
|
+
- Avoid waiting for "success" on sign in. Not everyone has it.
|
|
63
|
+
- Detect signature page variable names with the trigger variable name as a fallback to the `_save_as` input. If a server's config has its `restrict input variables` value set to `True`, the #trigger value is the only way for ALKiln to know which variable the signature is setting. Add an error to the report if ALKiln is unable to find either of those.
|
|
64
|
+
|
|
65
|
+
### Internal
|
|
66
|
+
|
|
67
|
+
- Handle non-existence of `elem` more robustly when checking for `elem.disabled`
|
|
68
|
+
- Add a pause between pull request tests and push tests when the PR is coming from our own repo
|
|
69
|
+
- Make getting page field values more robust by doing more to ensure that undefined option `value`s don't cause errors. For example, ajax combobox `select` options don't always have `value`s
|
|
47
70
|
|
|
48
71
|
## [5.9.0] - 2024-02-11
|
|
49
72
|
|
package/lib/cucumber_8_shim.js
CHANGED
package/lib/scope.js
CHANGED
|
@@ -626,7 +626,7 @@ module.exports = {
|
|
|
626
626
|
|
|
627
627
|
reports.addToReport(scope,{
|
|
628
628
|
type: `row`,
|
|
629
|
-
value: `Trying to load the interview at "${interview_url}"`
|
|
629
|
+
value: `Trying to load the interview at "${ interview_url }"`
|
|
630
630
|
});
|
|
631
631
|
|
|
632
632
|
if ( !scope.page ) { scope.page = await scope.browser.newPage(); }
|
|
@@ -641,8 +641,9 @@ module.exports = {
|
|
|
641
641
|
// If the page didn't load because it took to long to load
|
|
642
642
|
if ( error.name === `TimeoutError` ) {
|
|
643
643
|
|
|
644
|
-
let non_reload_report_msg = `Timeout error occurred when ALKiln tried to go to the interview
|
|
644
|
+
let non_reload_report_msg = `Timeout error occurred when ALKiln tried to go to the interview at ${ interview_url }`;
|
|
645
645
|
await scope.handle_page_timeout_error( scope, { non_reload_report_msg, error });
|
|
646
|
+
// TODO: Should this throw to avoid multiple error messages?
|
|
646
647
|
|
|
647
648
|
// If the page didn't load because of any other reason
|
|
648
649
|
} else {
|
|
@@ -650,7 +651,7 @@ module.exports = {
|
|
|
650
651
|
// Throw any non-timeout error
|
|
651
652
|
reports.addToReport( scope, {
|
|
652
653
|
type: `error`,
|
|
653
|
-
value: `Error occurred when ALKiln tried to go to the interview
|
|
654
|
+
value: `Error occurred when ALKiln tried to go to the interview at ${ interview_url }`
|
|
654
655
|
});
|
|
655
656
|
throw( error );
|
|
656
657
|
} // ends if error is timeout error
|
|
@@ -658,10 +659,12 @@ module.exports = {
|
|
|
658
659
|
} // ends try/catch
|
|
659
660
|
|
|
660
661
|
let load_result = await scope.getLoadData( scope );
|
|
661
|
-
//
|
|
662
|
+
// da page invalidation errors or timeout will show an error to the developer at the end
|
|
662
663
|
if ( load_result.error ) {
|
|
663
|
-
reports.addToReport(scope, { type: `error`, value: `On final attempt to load interview, got "${ load_result.error }"` });
|
|
664
|
+
reports.addToReport(scope, { type: `error`, value: `On final attempt to load interview at "${ interview_url }", got "${ load_result.error }"` });
|
|
664
665
|
expect( load_result.error ).to.equal( '' );
|
|
666
|
+
} else {
|
|
667
|
+
reports.addToReport(scope, { type: `info`, value: `Successfully found the interview at "${ interview_url }"` });
|
|
665
668
|
}
|
|
666
669
|
|
|
667
670
|
return scope.page;
|
|
@@ -693,6 +696,11 @@ module.exports = {
|
|
|
693
696
|
|
|
694
697
|
// or if they cause some other kind of error
|
|
695
698
|
} else {
|
|
699
|
+
reports.addToReport(scope, {
|
|
700
|
+
type: `error`,
|
|
701
|
+
value: `ALKiln got an error when it tried to load the interview page`,
|
|
702
|
+
data: error
|
|
703
|
+
});
|
|
696
704
|
throw error;
|
|
697
705
|
} // ends if error.name.includes(`TimeoutError`)
|
|
698
706
|
}); // ends Promise.race()
|
|
@@ -869,7 +877,29 @@ module.exports = {
|
|
|
869
877
|
if ( $(`#dasigpage`).length > 0 && $(`#dasigpage`)[0].name ) {
|
|
870
878
|
field_data.selector = `#daquestion canvas`;
|
|
871
879
|
field_data.tag = `canvas`;
|
|
872
|
-
|
|
880
|
+
|
|
881
|
+
// If da server's config value of `restrict input variables`
|
|
882
|
+
// set to True, `_save_as` should work to get the var name
|
|
883
|
+
if ( $( `input[name="_save_as"]` ).length > 0 ) {
|
|
884
|
+
not_decoded_name = $( `input[name="_save_as"]` ).attr( `value` );
|
|
885
|
+
|
|
886
|
+
// If not, the author will have to use the trigger var HTML element
|
|
887
|
+
// or we can't get the var name being set for the signature
|
|
888
|
+
} else if ( trigger !== `` ) {
|
|
889
|
+
not_decoded_name = trigger;
|
|
890
|
+
|
|
891
|
+
// If we have neither of those, we need to tell the user we can't
|
|
892
|
+
// set this variable this way. We can't test this without a
|
|
893
|
+
// server that has that special config value set to `True`
|
|
894
|
+
} else {
|
|
895
|
+
reports.addToReport(scope, {
|
|
896
|
+
type: `error`,
|
|
897
|
+
value: `You cannot sign a signature page this way because the `
|
|
898
|
+
+ `interview's HTML is missing data. Use the "I sign" Step `
|
|
899
|
+
+ `instead. You can also read documentation about `
|
|
900
|
+
+ `how to create the "trigger" HTML.`
|
|
901
|
+
});
|
|
902
|
+
}
|
|
873
903
|
}
|
|
874
904
|
|
|
875
905
|
// The selector we'll use to set the DOM node's value later
|
|
@@ -983,6 +1013,7 @@ module.exports = {
|
|
|
983
1013
|
/* Return variable names and values combined in ways that can
|
|
984
1014
|
* try to match table rows. Tables can have two properties:
|
|
985
1015
|
* variable name and value. */
|
|
1016
|
+
if ( session_vars.get_debug() ) { console.log(`scope.getPossibleTableRowMatchers() var_names:`, var_names, `values:`, values); }
|
|
986
1017
|
let possible_table_rows = [];
|
|
987
1018
|
for ( let var_name of var_names ) {
|
|
988
1019
|
// Inputs like textareas don't have values
|
|
@@ -993,7 +1024,8 @@ module.exports = {
|
|
|
993
1024
|
// Modified from https://stackoverflow.com/a/8571649/11416267
|
|
994
1025
|
// DA doesn't use `==` to pad base 64
|
|
995
1026
|
// TODO: How are 'None', 'True', and 'False' being handled?
|
|
996
|
-
if (value !==
|
|
1027
|
+
if (value !== undefined && value !== null
|
|
1028
|
+
&& value !== 'None' && value !== 'True' && value !== 'False'
|
|
997
1029
|
&& value.match(da_base64_regex)) {
|
|
998
1030
|
let value_decoded = fromBase64(value);
|
|
999
1031
|
let values_decoded = scope.decodeFully( scope, { expr_str: value_decoded });
|
|
@@ -1246,7 +1278,10 @@ module.exports = {
|
|
|
1246
1278
|
let options = [];
|
|
1247
1279
|
let option_nodes = $select.find( `option` );
|
|
1248
1280
|
for ( let opt of option_nodes ) {
|
|
1249
|
-
options
|
|
1281
|
+
// Some options don't have a value, like for ajax comboboxes
|
|
1282
|
+
if ( opt.attribs.value !== undefined ) {
|
|
1283
|
+
options.push( opt.attribs.value );
|
|
1284
|
+
}
|
|
1250
1285
|
// Dropdowns created w/ objects are base64 encoded; but it's handled in getPossibleTableRowMatchers
|
|
1251
1286
|
}
|
|
1252
1287
|
return options;
|
|
@@ -1490,6 +1525,7 @@ module.exports = {
|
|
|
1490
1525
|
}
|
|
1491
1526
|
|
|
1492
1527
|
let handle = await scope.get_handle_from_field( scope, { field: field });
|
|
1528
|
+
// TODO: expect elem to exist
|
|
1493
1529
|
|
|
1494
1530
|
// After each previous input, figure out if this input is (now/still) disabled
|
|
1495
1531
|
// TODO: Consider testing for disabled this before we get the matching row
|
|
@@ -1498,8 +1534,12 @@ module.exports = {
|
|
|
1498
1534
|
// sometimes it blocks nodes from clicks. Scroll item to the bottom instead.
|
|
1499
1535
|
// Note: I'm not sure how we'd get in here if `elem` didn't exist, but
|
|
1500
1536
|
// I once got an error here that I couldn't read `.disabled` of `null`.
|
|
1501
|
-
if ( elem && !elem.disabled ) {
|
|
1502
|
-
|
|
1537
|
+
if ( elem && !elem.disabled ) {
|
|
1538
|
+
elem.scrollIntoView(false);
|
|
1539
|
+
return elem.disabled;
|
|
1540
|
+
} else {
|
|
1541
|
+
return false;
|
|
1542
|
+
}
|
|
1503
1543
|
});
|
|
1504
1544
|
|
|
1505
1545
|
// If field is disabled, don't set it yet
|
|
@@ -1531,7 +1571,9 @@ module.exports = {
|
|
|
1531
1571
|
|
|
1532
1572
|
get_handle_from_field: async function ( scope, { field }) {
|
|
1533
1573
|
/** Get the element's puppeteer handle using the field's selector. */
|
|
1534
|
-
|
|
1574
|
+
if ( session_vars.get_debug() ) {
|
|
1575
|
+
console.log(`scope.get_handle_from_field() field.selector:`, field.selector );
|
|
1576
|
+
}
|
|
1535
1577
|
let handle = await scope.page.evaluateHandle(( selector ) => {
|
|
1536
1578
|
let elem = document.querySelector( selector );
|
|
1537
1579
|
// If the element has a sibling that's a label, we need to
|
|
@@ -1758,7 +1800,9 @@ module.exports = {
|
|
|
1758
1800
|
// Authors should enter the time like 12:34 PM, but we shouldn't type ":", space, or M.
|
|
1759
1801
|
let answer_time = answer.replace(":", "").replace(" ", "").replace("M", "");
|
|
1760
1802
|
await handle.focus();
|
|
1761
|
-
|
|
1803
|
+
let delay = 0;
|
|
1804
|
+
if ( session_vars.get_debug() ) { delay = 25; }
|
|
1805
|
+
await handle.type( answer, { delay });
|
|
1762
1806
|
await handle.press(`Enter`);
|
|
1763
1807
|
await scope.afterStep(scope, { waitForShowIf: true });
|
|
1764
1808
|
} else {
|
|
@@ -1932,9 +1976,16 @@ module.exports = {
|
|
|
1932
1976
|
|
|
1933
1977
|
setText: async function ( scope, { handle, answer }) {
|
|
1934
1978
|
// Set text in some kind of field (input text, input date, textarea, etc.)
|
|
1935
|
-
|
|
1979
|
+
// First set the value to part of the string
|
|
1980
|
+
const to_set = answer.slice(0, -3);
|
|
1981
|
+
const to_type = answer.slice(-3);
|
|
1982
|
+
await handle.evaluate(( elem, text ) => {
|
|
1983
|
+
elem.value = text;
|
|
1984
|
+
}, to_set );
|
|
1985
|
+
// Then type the last three characters of the string with a
|
|
1986
|
+
// good pause to let the field register the interaction
|
|
1936
1987
|
await handle.focus();
|
|
1937
|
-
await handle.type(
|
|
1988
|
+
await handle.type( to_type, { delay: 100 });
|
|
1938
1989
|
},
|
|
1939
1990
|
|
|
1940
1991
|
draw_signature: async function ( scope, name ) {
|
|
@@ -2060,6 +2111,8 @@ module.exports = {
|
|
|
2060
2111
|
} // ends for every non-submit-button field on the page
|
|
2061
2112
|
} // ends while fields are still being set
|
|
2062
2113
|
|
|
2114
|
+
if ( session_vars.get_debug() ) { await scope.page.waitForTimeout(2000); }
|
|
2115
|
+
|
|
2063
2116
|
// Press a continue button with a story table variable name if it exists
|
|
2064
2117
|
let did_navigate = false;
|
|
2065
2118
|
let error = {};
|
|
@@ -2838,11 +2891,6 @@ module.exports = {
|
|
|
2838
2891
|
let elem = await scope.page.$( `button[name="submit"]` );
|
|
2839
2892
|
await scope.tapElementAndNavigate( scope, { elem });
|
|
2840
2893
|
|
|
2841
|
-
// Wait to see the success message.
|
|
2842
|
-
// This is a bit of an assumption and needs success and failure testing
|
|
2843
|
-
// TODO: use a Promise.race to fail faster.
|
|
2844
|
-
await scope.page.waitForSelector( `.datopcenter .alert-success` );
|
|
2845
|
-
|
|
2846
2894
|
reports.addToReport( scope, {
|
|
2847
2895
|
type: `row`,
|
|
2848
2896
|
value: `Signed into ${ session_vars.get_da_server_url() }/user/sign-in successfully.`
|
package/lib/steps.js
CHANGED
|
@@ -114,7 +114,7 @@ Before(async (scenario) => {
|
|
|
114
114
|
|
|
115
115
|
// Create browser, which can't be created in BeforeAll() where .driver doesn't exist for some reason
|
|
116
116
|
if (!scope.browser) {
|
|
117
|
-
if (session_vars.get_origin()
|
|
117
|
+
if ( session_vars.get_origin() !== `local` ) {
|
|
118
118
|
// Will only run in the Playground outside of a sandbox. TODO: There's a
|
|
119
119
|
// better way to do this, though it's more complicated. See comments in
|
|
120
120
|
// https://github.com/SuffolkLITLab/ALKiln/issues/661
|
|
@@ -178,11 +178,12 @@ Given(/I start the interview at "([^"]+)"/, {timeout: -1}, async (file_name) =>
|
|
|
178
178
|
await scope.load( scope, file_name );
|
|
179
179
|
|
|
180
180
|
// The page timeout is set in here too in case someone set a custom timeout
|
|
181
|
-
// before a page was loaded.
|
|
181
|
+
// just before a page was loaded for the Scenario. Move this to just after page creation?
|
|
182
182
|
// The function itself won't really timeout here, so we don't need to wrap it in
|
|
183
183
|
// a custom timeout
|
|
184
184
|
await scope.page.setDefaultTimeout( scope.timeout ); // overrides outer default timeout
|
|
185
185
|
|
|
186
|
+
// TODO: Move this to the `download` Step and only do it once per scenario
|
|
186
187
|
// Allow developer to save download files
|
|
187
188
|
let custom_download_behavior_timeout = new Promise(async ( resolve, reject ) => {
|
|
188
189
|
let page_timeout = setTimeout(function() {reject( `Took too long to set download behavior.` ); }, scope.timeout);
|
|
@@ -236,6 +237,8 @@ Given(/I start the interview at "([^"]+)"/, {timeout: -1}, async (file_name) =>
|
|
|
236
237
|
} // ends if this is the file the developer expected
|
|
237
238
|
}); // ends page.on 'response'
|
|
238
239
|
|
|
240
|
+
// TODO: Wrap everything in this step in this timeout? Or is this Step's timeout different?
|
|
241
|
+
// Wait for navigation
|
|
239
242
|
let custom_afterStep_timeout = new Promise(async ( resolve, reject ) => {
|
|
240
243
|
let page_timeout = setTimeout(function() { reject(`\`afterStep()\` took too long.`); }, scope.timeout);
|
|
241
244
|
// self-invoke an anonymous async function so we don't have to
|
|
@@ -251,6 +254,22 @@ Given(/I start the interview at "([^"]+)"/, {timeout: -1}, async (file_name) =>
|
|
|
251
254
|
await custom_afterStep_timeout;
|
|
252
255
|
});
|
|
253
256
|
|
|
257
|
+
Given(/I go to "([^"]+)"/i, {timeout: -1}, async ( url ) => {
|
|
258
|
+
/** Navigate to an arbitrary url. What you do after that depends on you. There's
|
|
259
|
+
* a limited amount ALKiln can do on a non-docassemble page or a very customized
|
|
260
|
+
* docassemble page.
|
|
261
|
+
*
|
|
262
|
+
* @params {string} A valid url */
|
|
263
|
+
let result = await wrapPromiseWithTimeout(
|
|
264
|
+
scope.page.goto( url, { waitUntil: 'domcontentloaded', timeout: scope.timeout }),
|
|
265
|
+
scope.timeout,
|
|
266
|
+
`It took to long to get to "${ url }"`
|
|
267
|
+
);
|
|
268
|
+
|
|
269
|
+
reports.addToReport(scope, { type: `info`, value: `Successfully went to "${ url }"` });
|
|
270
|
+
return result;
|
|
271
|
+
});
|
|
272
|
+
|
|
254
273
|
Given(/I (?:sign|log) ?(?:in)?(?:on)?(?:to the server)? with(?: the email)? "([^"]+)" and(?: the password)? "([^"]+)"(?: SECRETs)?/i, {timeout: -1}, async ( email, password ) => {
|
|
255
274
|
/** Uses the names of environment variables (most often GitHub SECRETs) to
|
|
256
275
|
* log into an account on the user's server. Must be SECRETs to stay secure.
|
|
@@ -294,7 +294,7 @@ session_vars.set_sources_paths = function ( paths ) {
|
|
|
294
294
|
}
|
|
295
295
|
|
|
296
296
|
console.info(
|
|
297
|
-
`ALKiln
|
|
297
|
+
`ALKiln SUCCESS: Did find "sources" file(s) at "${ existing_paths.join('", "') }".`
|
|
298
298
|
)
|
|
299
299
|
|
|
300
300
|
// Otherwise, store valid paths
|
package/package.json
CHANGED
|
@@ -1108,6 +1108,76 @@ fields.object_multiselect = [
|
|
|
1108
1108
|
},
|
|
1109
1109
|
];
|
|
1110
1110
|
|
|
1111
|
+
// ============================
|
|
1112
|
+
// Ajax combobox
|
|
1113
|
+
// ============================
|
|
1114
|
+
fields.ajax = [
|
|
1115
|
+
{
|
|
1116
|
+
"selector": "#daquestion input[name=\"ZmF2b3JpdGVfd29yZA\"]",
|
|
1117
|
+
"tag": "input",
|
|
1118
|
+
"guesses": [
|
|
1119
|
+
{
|
|
1120
|
+
"var": "ZmF2b3JpdGVfd29yZA",
|
|
1121
|
+
"value": ""
|
|
1122
|
+
},
|
|
1123
|
+
{
|
|
1124
|
+
"var": "favorite_word",
|
|
1125
|
+
"value": ""
|
|
1126
|
+
}
|
|
1127
|
+
],
|
|
1128
|
+
"type": "hidden",
|
|
1129
|
+
"trigger": ""
|
|
1130
|
+
},
|
|
1131
|
+
{
|
|
1132
|
+
"selector": "#daquestion input[id=\"ZmF2b3JpdGVfd29yZA\"][class=\"form-control da-ajax-combobox\"]",
|
|
1133
|
+
"tag": "input",
|
|
1134
|
+
"guesses": [
|
|
1135
|
+
{
|
|
1136
|
+
"var": "ZmF2b3JpdGVfd29yZA",
|
|
1137
|
+
"value": ""
|
|
1138
|
+
},
|
|
1139
|
+
{
|
|
1140
|
+
"var": "favorite_word",
|
|
1141
|
+
"value": ""
|
|
1142
|
+
}
|
|
1143
|
+
],
|
|
1144
|
+
"type": "text",
|
|
1145
|
+
"trigger": ""
|
|
1146
|
+
},
|
|
1147
|
+
{
|
|
1148
|
+
"selector": "#daquestion select[id=\"ZmF2b3JpdGVfd29yZAcombobox\"][class=\"form-control da-ajax-combobox\"]",
|
|
1149
|
+
"tag": "select",
|
|
1150
|
+
"guesses": [
|
|
1151
|
+
{
|
|
1152
|
+
"var": "ZmF2b3JpdGVfd29yZAcombobox",
|
|
1153
|
+
"value": ""
|
|
1154
|
+
},
|
|
1155
|
+
{
|
|
1156
|
+
"var": "favorite_word\u0007(��\u001b�",
|
|
1157
|
+
"value": ""
|
|
1158
|
+
}
|
|
1159
|
+
],
|
|
1160
|
+
"type": "",
|
|
1161
|
+
"trigger": ""
|
|
1162
|
+
},
|
|
1163
|
+
{
|
|
1164
|
+
"selector": "#daquestion button[id=\"da-continue-button\"][class=\"btn btn-da btn-primary\"]",
|
|
1165
|
+
"tag": "button",
|
|
1166
|
+
"guesses": [
|
|
1167
|
+
{
|
|
1168
|
+
"var": "da-continue-button",
|
|
1169
|
+
"value": ""
|
|
1170
|
+
},
|
|
1171
|
+
{
|
|
1172
|
+
"var": "u���{b��n�m�",
|
|
1173
|
+
"value": ""
|
|
1174
|
+
}
|
|
1175
|
+
],
|
|
1176
|
+
"type": "submit",
|
|
1177
|
+
"trigger": ""
|
|
1178
|
+
}
|
|
1179
|
+
];
|
|
1180
|
+
|
|
1111
1181
|
|
|
1112
1182
|
// ============================
|
|
1113
1183
|
// mixed quotes
|
|
@@ -33,8 +33,8 @@ chai.config.truncateThreshold = 0
|
|
|
33
33
|
it(`creates the right data for standard fields`, async function() {
|
|
34
34
|
// 18 fields (03/15/21)
|
|
35
35
|
let result = await getAllFields( scope, { html: html.standard });
|
|
36
|
-
//
|
|
37
|
-
//
|
|
36
|
+
// console.log(`=================\n${ JSON.stringify(fields.standard, null, 2) }`);
|
|
37
|
+
// console.log(`-----------------\n${ JSON.stringify(result, null, 2) }`);
|
|
38
38
|
expect( result ).to.deep.equalInAnyOrder( fields.standard );
|
|
39
39
|
});
|
|
40
40
|
|
|
@@ -148,6 +148,12 @@ it(`creates the right data for a dropdown created with an object`, async functio
|
|
|
148
148
|
expect( result ).to.deep.equalInAnyOrder(fields.object_dropdown );
|
|
149
149
|
});
|
|
150
150
|
|
|
151
|
+
// Ajax
|
|
152
|
+
it('creates the right data for an `ajax` combobox', async function() {
|
|
153
|
+
let result = await getAllFields( scope, { html: html.ajax });
|
|
154
|
+
expect( result ).to.deep.equalInAnyOrder(fields.ajax );
|
|
155
|
+
});
|
|
156
|
+
|
|
151
157
|
// ============================
|
|
152
158
|
// DOM for mixed quotes test in getMatchingRows.test.js
|
|
153
159
|
// ============================
|
|
@@ -789,6 +789,62 @@ html.object_dropdown = `
|
|
|
789
789
|
</form>
|
|
790
790
|
</div>`;
|
|
791
791
|
|
|
792
|
+
html.ajax = `
|
|
793
|
+
<div id="daquestion" aria-labelledby="dapagetitle" role="main" class="tab-pane fade show active offset-lg-3 col-lg-6 offset-md-2 col-md-8">
|
|
794
|
+
<form aria-labelledby="daMainQuestion" action="/interview?i=docassemble.base:data/questions/examples/fields-ajax.yml" id="daform" class="form-horizontal daformfields" method="POST" novalidate="novalidate">
|
|
795
|
+
<div class="da-page-header">
|
|
796
|
+
<h1 class="h3" id="daMainQuestion">What is your favorite word?</h1>
|
|
797
|
+
<div class="daclear"></div>
|
|
798
|
+
</div>
|
|
799
|
+
<div
|
|
800
|
+
class="da-container da-form-group row darequired da-field-container da-field-container-datatype-text da-field-container-inputtype-ajax">
|
|
801
|
+
<label for="ZmF2b3JpdGVfd29yZA" class="col-md-4 col-form-label da-form-label datext-right" >Word</label>
|
|
802
|
+
<div class="col-md-8 dafieldpart">
|
|
803
|
+
<div class="combobox-container">
|
|
804
|
+
<input type="hidden" name="ZmF2b3JpdGVfd29yZA" value="" />
|
|
805
|
+
<div class="input-group">
|
|
806
|
+
<input type="text" role="combobox" aria-autocomplete="list" aria-expanded="false" aria-activedescendant="" autocomplete="off" id="ZmF2b3JpdGVfd29yZA" aria-controls="ZmF2b3JpdGVfd29yZAmenu" aria-owns="ZmF2b3JpdGVfd29yZAmenu" placeholder="" required="required" class="form-control da-ajax-combobox"/>
|
|
807
|
+
<ul role="listbox" class="typeahead typeahead-long dropdown-menu" id="ZmF2b3JpdGVfd29yZAmenu"></ul>
|
|
808
|
+
<div class="input-group-append">
|
|
809
|
+
<button class="btn btn-outline-secondary dacomboboxtoggle" type="button" tabindex="-1" aria-label="Dropdown" aria-expanded="false" aria-controls="ZmF2b3JpdGVfd29yZAmenu">
|
|
810
|
+
<svg class="svg-inline--fa fa-caret-down"></svg
|
|
811
|
+
><!-- <span class="fas fa-xmark"></span> Font Awesome fontawesome.com -->
|
|
812
|
+
</button>
|
|
813
|
+
</div>
|
|
814
|
+
</div>
|
|
815
|
+
</div>
|
|
816
|
+
<select data-action="wordlist" data-trig="4" alt="Input box" class="form-control da-ajax-combobox" id="ZmF2b3JpdGVfd29yZAcombobox" required="" style="display: none;">
|
|
817
|
+
<option selected="selected"></option>
|
|
818
|
+
</select>
|
|
819
|
+
</div>
|
|
820
|
+
</div>
|
|
821
|
+
<fieldset class="da-button-set da-field-buttons">
|
|
822
|
+
<legend class="visually-hidden">
|
|
823
|
+
Press one of the following buttons:
|
|
824
|
+
</legend>
|
|
825
|
+
<button class="btn btn-da btn-primary" id="da-continue-button" type="submit">
|
|
826
|
+
Continue
|
|
827
|
+
</button>
|
|
828
|
+
</fieldset>
|
|
829
|
+
<input
|
|
830
|
+
type="hidden"
|
|
831
|
+
name="csrf_token"
|
|
832
|
+
value="ImI4NDAyMmI3Mjc4NGY3MDlkMTRiNGE5OTQzZDhmZTVhYWY5NzQwNzUi.ZdVoHQ.GLQUgOWjNag9f7jGSiO9ZvHDoEc"
|
|
833
|
+
/>
|
|
834
|
+
<input type="hidden" name="_question_name" value="Question_0" />
|
|
835
|
+
<input type="hidden" name="_tracker" value="2" />
|
|
836
|
+
<input type="hidden" name="_visible" value="" />
|
|
837
|
+
<input
|
|
838
|
+
type="hidden"
|
|
839
|
+
name="_varnames"
|
|
840
|
+
value="eyJYMlpwWld4a1h6QSI6ICJabUYyYjNKcGRHVmZkMjl5WkEifQ"
|
|
841
|
+
/>
|
|
842
|
+
</form>
|
|
843
|
+
</div>`;
|
|
844
|
+
|
|
845
|
+
// ============================
|
|
846
|
+
// quotes
|
|
847
|
+
// ============================
|
|
792
848
|
html.mixed_quotes = `
|
|
793
849
|
<div id="daquestion" aria-labelledby="dapagetitle" role="main" class="tab-pane fade show active offset-xl-3 offset-lg-3 col-xl-6 col-lg-6 offset-md-2 col-md-8">
|
|
794
850
|
<div data-variable="ZG91YmxlX3F1b3RlX2RpY3RbJ2RvdWJsZV9xdW90ZV9rZXknXQ" id="trigger" aria-hidden="true" style="display: none;"></div>
|
|
@@ -892,5 +948,4 @@ html.mixed_quotes = `
|
|
|
892
948
|
</form>
|
|
893
949
|
</div>`;
|
|
894
950
|
|
|
895
|
-
|
|
896
951
|
module.exports = html;
|