@suffolklitlab/alkiln 5.2.0 → 5.2.1
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/CHANGELOG.md +13 -0
- package/lib/scope.js +83 -47
- package/lib/steps.js +1 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -44,7 +44,20 @@ Format:
|
|
|
44
44
|
-->
|
|
45
45
|
<!-- ## [Unreleased] -->
|
|
46
46
|
|
|
47
|
+
## [5.2.1] - 2023-09-29
|
|
48
|
+
|
|
49
|
+
### Added
|
|
50
|
+
- New warning message to the developer when their date string doesn't have a `/` in it.
|
|
51
|
+
|
|
52
|
+
### Changed
|
|
53
|
+
- Told the user the url of the interview ALKiln tried to load. See https://github.com/SuffolkLITLab/ALKiln/issues/696.
|
|
54
|
+
|
|
55
|
+
### Fixed
|
|
56
|
+
- Restored Assembly Line custom datatype three-parts dates functionality. See https://github.com/SuffolkLITLab/ALKiln/issues/764.
|
|
57
|
+
- Fixed "today" not being converted into a date for custom datatypes.
|
|
58
|
+
|
|
47
59
|
## [5.2.0] - 2023-09-16
|
|
60
|
+
|
|
48
61
|
### Changed
|
|
49
62
|
- Make `I tap to continue` case insensitive to allow the author to match the capitalization of the button in Docassemble.
|
|
50
63
|
|
package/lib/scope.js
CHANGED
|
@@ -616,22 +616,22 @@ module.exports = {
|
|
|
616
616
|
* https://github.com/puppeteer/puppeteer/issues/299 and
|
|
617
617
|
*/
|
|
618
618
|
|
|
619
|
+
// If file has finished downloading
|
|
620
|
+
if ( scope.downloadComplete ) {
|
|
621
|
+
// reset the flag and resolve
|
|
622
|
+
scope.downloadComplete = false;
|
|
623
|
+
return true;
|
|
624
|
+
}
|
|
625
|
+
|
|
619
626
|
// Stop/resolve if too much time has passed
|
|
620
627
|
let expirationTime = scope.timeout - 200; // ms
|
|
621
628
|
if ( !endTime ) { endTime = new Date((new Date()).getTime() + expirationTime); }
|
|
622
629
|
let diff = endTime.getTime() - Date.now();
|
|
623
630
|
if ( diff <= 0 ) { return false; }
|
|
624
631
|
|
|
625
|
-
// If time hasn't expired
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
scope.downloadComplete = false;
|
|
629
|
-
return true;
|
|
630
|
-
} else {
|
|
631
|
-
// Otherwise wait and then check again
|
|
632
|
-
await scope.page.waitForTimeout( 100 );
|
|
633
|
-
await scope.detectDownloadComplete(scope, endTime);
|
|
634
|
-
}
|
|
632
|
+
// If time hasn't expired, wait and then check again
|
|
633
|
+
await scope.page.waitForTimeout( 100 );
|
|
634
|
+
await scope.detectDownloadComplete(scope, endTime);
|
|
635
635
|
|
|
636
636
|
return false;
|
|
637
637
|
},
|
|
@@ -732,11 +732,6 @@ module.exports = {
|
|
|
732
732
|
/* Try to load the page. Should we also pass a `timeout` arg or just
|
|
733
733
|
* use scope.timeout? */
|
|
734
734
|
|
|
735
|
-
await scope.addToReport(scope,{
|
|
736
|
-
type: `row`,
|
|
737
|
-
value: `Trying to load the interview`
|
|
738
|
-
});
|
|
739
|
-
|
|
740
735
|
let interview_url = null;
|
|
741
736
|
// If the file is already a full url, just use that arbitrary url
|
|
742
737
|
if ( /^http/.test( file_name ) ) {
|
|
@@ -752,7 +747,11 @@ module.exports = {
|
|
|
752
747
|
let base_url = await get_base_interview_url();
|
|
753
748
|
interview_url = `${ base_url }${ file_name }`;
|
|
754
749
|
}
|
|
755
|
-
|
|
750
|
+
|
|
751
|
+
await scope.addToReport(scope,{
|
|
752
|
+
type: `row`,
|
|
753
|
+
value: `Trying to load the interview at "${interview_url}"`
|
|
754
|
+
});
|
|
756
755
|
|
|
757
756
|
if ( !scope.page ) { scope.page = await scope.browser.newPage(); }
|
|
758
757
|
|
|
@@ -1477,11 +1476,6 @@ module.exports = {
|
|
|
1477
1476
|
*/
|
|
1478
1477
|
let row_used = null;
|
|
1479
1478
|
|
|
1480
|
-
// Skip hidden fields right away. When a date field was above a combobox,
|
|
1481
|
-
// interacting with the hidden field caused the date field to open its
|
|
1482
|
-
// calendar which blocked input to the combobox
|
|
1483
|
-
if ( field.type === `hidden` ) { return row_used; }
|
|
1484
|
-
|
|
1485
1479
|
let matching_input_rows = await scope.getMatchingRows( scope, { var_data, field });
|
|
1486
1480
|
|
|
1487
1481
|
// Nothing to set if there are no matching table rows
|
|
@@ -1597,8 +1591,16 @@ module.exports = {
|
|
|
1597
1591
|
row_was_used = await scope.setCustomDatatype[ custom_datatype ]( scope, { handle: custom_handle, answer });
|
|
1598
1592
|
} else {
|
|
1599
1593
|
// If no custom datatype, set a regular field
|
|
1600
|
-
|
|
1601
|
-
|
|
1594
|
+
|
|
1595
|
+
// Skip hidden fields. When a `show if` date field is above a combobox,
|
|
1596
|
+
// interacting with the hidden field causes the date field to open its
|
|
1597
|
+
// calendar which blocks input to the combobox
|
|
1598
|
+
if ( field.type === `hidden` ) {
|
|
1599
|
+
row_was_used = false;
|
|
1600
|
+
} else {
|
|
1601
|
+
row_was_used = await scope.enter_answer[ field.tag ]( scope, { handle, answer });
|
|
1602
|
+
}
|
|
1603
|
+
} // ends if custom datatype
|
|
1602
1604
|
|
|
1603
1605
|
return row_was_used;
|
|
1604
1606
|
}, // Ends scope.funnel_the_answer()
|
|
@@ -1614,8 +1616,12 @@ module.exports = {
|
|
|
1614
1616
|
|
|
1615
1617
|
// If it doesn't have the right format
|
|
1616
1618
|
if ( answer === null || !answer.includes(`/`) ) {
|
|
1617
|
-
//
|
|
1618
|
-
|
|
1619
|
+
// Return field unused.
|
|
1620
|
+
await scope.addToReport( scope, {
|
|
1621
|
+
type: `warning`,
|
|
1622
|
+
value: `Invalid date. Value given: "${ answer }".`
|
|
1623
|
+
});
|
|
1624
|
+
return false;
|
|
1619
1625
|
}
|
|
1620
1626
|
|
|
1621
1627
|
let date_parts = answer.split(`/`);
|
|
@@ -1636,18 +1642,20 @@ module.exports = {
|
|
|
1636
1642
|
handle: field,
|
|
1637
1643
|
answer: date_parts[ field_i ]
|
|
1638
1644
|
});
|
|
1645
|
+
await handle.press(`Tab`);
|
|
1639
1646
|
}
|
|
1640
1647
|
|
|
1641
1648
|
} // For each field
|
|
1642
1649
|
|
|
1643
1650
|
await scope.afterStep( scope );
|
|
1651
|
+
return true;
|
|
1644
1652
|
}, // Ends scope.setCustomDatatype.al_date()
|
|
1645
1653
|
|
|
1646
1654
|
BirthDate: async function ( scope, { handle, answer }) {
|
|
1647
1655
|
/** Given a date of the format 'mm/dd/yyyy' and the handle of the
|
|
1648
1656
|
* custom field container, sets the ALToolbox custom birthdate
|
|
1649
1657
|
* field values. */
|
|
1650
|
-
|
|
1658
|
+
answer = await scope.today_to_date(scope, { date: answer });
|
|
1651
1659
|
await scope.setCustomDatatype.al_date( scope, { handle, answer })
|
|
1652
1660
|
}, // Ends scope.setCustomDatatype.BirthDate()
|
|
1653
1661
|
|
|
@@ -1655,6 +1663,7 @@ module.exports = {
|
|
|
1655
1663
|
/** Given a date of the format 'mm/dd/yyyy' and the handle of the
|
|
1656
1664
|
* custom field container, sets the ALToolbox custom ThreePartsDate
|
|
1657
1665
|
* field values. */
|
|
1666
|
+
answer = await scope.today_to_date(scope, { date: answer });
|
|
1658
1667
|
await scope.setCustomDatatype.al_date( scope, { handle, answer })
|
|
1659
1668
|
}, // Ends scope.setCustomDatatype.ThreePartsDate()
|
|
1660
1669
|
|
|
@@ -1729,36 +1738,20 @@ module.exports = {
|
|
|
1729
1738
|
await scope.afterStep(scope, { waitForShowIf: true });
|
|
1730
1739
|
|
|
1731
1740
|
} else if (type == `date`) {
|
|
1732
|
-
let answer_date = answer;
|
|
1733
|
-
// If the date is specified in the format "today" or "today + 2" or "today-1"
|
|
1734
|
-
// it will need some pre-processing.
|
|
1735
|
-
if (answer.indexOf(`today`) !== -1) {
|
|
1736
|
-
// Find out how many days to add/subtract
|
|
1737
|
-
let date_delta = answer.replace(/\s/g, '');
|
|
1738
|
-
date_delta = date_delta.match(/today([+-]\d+)?/)[1];
|
|
1739
|
-
date_delta = date_delta == undefined ? 0 : date_delta;
|
|
1740
|
-
date_delta = parseInt(date_delta);
|
|
1741
|
-
// Get today's date
|
|
1742
|
-
answer_date = new Date();
|
|
1743
|
-
// Add/subtract required number of days
|
|
1744
|
-
answer_date.setDate(answer_date.getDate() + date_delta);
|
|
1745
|
-
// Convert to the docassemble date field format: mm/dd/yyyy
|
|
1746
|
-
// Reference: https://gomakethings.com/setting-a-date-input-to-todays-date-with-vanilla-js/
|
|
1747
|
-
answer_date = ((answer_date.getMonth() + 1).toString().padStart(2, 0) + '/' +
|
|
1748
|
-
answer_date.getDate().toString().padStart(2, 0) + '/' +
|
|
1749
|
-
answer_date.getFullYear().toString());
|
|
1750
|
-
}
|
|
1741
|
+
let answer_date = await scope.today_to_date(scope, { date: answer });
|
|
1751
1742
|
await scope.setText( scope, { handle, answer: answer_date });
|
|
1743
|
+
await handle.press(`Tab`);
|
|
1752
1744
|
await scope.afterStep(scope, { waitForShowIf: true });
|
|
1753
1745
|
} else if (type == `time`) {
|
|
1754
1746
|
// Authors should enter the time like 12:34 PM, but we shouldn't type ":", space, or M.
|
|
1755
1747
|
let answer_time = answer.replace(":", "").replace(" ", "").replace("M", "");
|
|
1756
1748
|
await handle.focus();
|
|
1757
1749
|
await handle.type( answer );
|
|
1758
|
-
await handle.press(
|
|
1750
|
+
await handle.press(`Enter`);
|
|
1759
1751
|
await scope.afterStep(scope, { waitForShowIf: true });
|
|
1760
1752
|
} else {
|
|
1761
1753
|
await scope.setText( scope, { handle, answer });
|
|
1754
|
+
await handle.press(`Tab`);
|
|
1762
1755
|
await scope.afterStep(scope, { waitForShowIf: true });
|
|
1763
1756
|
}
|
|
1764
1757
|
|
|
@@ -1774,7 +1767,50 @@ module.exports = {
|
|
|
1774
1767
|
return;
|
|
1775
1768
|
},
|
|
1776
1769
|
|
|
1777
|
-
}, // ends scope.enter_answer
|
|
1770
|
+
}, // ends scope.enter_answer()
|
|
1771
|
+
|
|
1772
|
+
today_to_date: async function ( scope, { date }) {
|
|
1773
|
+
/** Return `date` or, if the date is specified in the format
|
|
1774
|
+
* "today" or "today + 2" or "today-1", return a date of the format
|
|
1775
|
+
* "mm/dd/yyyy".
|
|
1776
|
+
*
|
|
1777
|
+
* @param scope { obj } REQUIRED. Object with test state.
|
|
1778
|
+
* @param date { str } REQUIRED. Input from the developer.
|
|
1779
|
+
*
|
|
1780
|
+
* @returns { str } `date` or "today" math as date str
|
|
1781
|
+
*
|
|
1782
|
+
* WARNING: If the developer is counting on date boundaries to trigger
|
|
1783
|
+
* other logic then timezone differences may interfere with that. They
|
|
1784
|
+
* should:
|
|
1785
|
+
*
|
|
1786
|
+
* 1. Test with a day well within the date range they're testing instead
|
|
1787
|
+
* of near a boundary. For example, test 8 days from now instead of 10.
|
|
1788
|
+
* This is because their test may run around 12am and thus be vulnerable
|
|
1789
|
+
* to failure.
|
|
1790
|
+
* 2. Warn the user explicitly and let them know when they need to file by
|
|
1791
|
+
* in case the user doesn't know and files a few days from the day they filled
|
|
1792
|
+
* out the form.
|
|
1793
|
+
*/
|
|
1794
|
+
let valid_date = date;
|
|
1795
|
+
if (date.indexOf(`today`) !== -1) {
|
|
1796
|
+
// Find out how many days to add/subtract
|
|
1797
|
+
let date_delta = date.replace(/\s/g, '');
|
|
1798
|
+
date_delta = date_delta.match(/today([+-]\d+)?/)[1];
|
|
1799
|
+
date_delta = date_delta == undefined ? 0 : date_delta;
|
|
1800
|
+
date_delta = parseInt(date_delta);
|
|
1801
|
+
// Get today's date
|
|
1802
|
+
valid_date = new Date();
|
|
1803
|
+
// Add/subtract required number of days
|
|
1804
|
+
valid_date.setDate(valid_date.getDate() + date_delta);
|
|
1805
|
+
// Convert to the docassemble date field format: mm/dd/yyyy
|
|
1806
|
+
// Reference: https://gomakethings.com/setting-a-date-input-to-todays-date-with-vanilla-js/
|
|
1807
|
+
valid_date = ((valid_date.getMonth() + 1).toString().padStart(2, 0) + '/' +
|
|
1808
|
+
valid_date.getDate().toString().padStart(2, 0) + '/' +
|
|
1809
|
+
valid_date.getFullYear().toString());
|
|
1810
|
+
}
|
|
1811
|
+
|
|
1812
|
+
return valid_date;
|
|
1813
|
+
}, // Ends scope.today_to_date()
|
|
1778
1814
|
|
|
1779
1815
|
uploadFiles: async function ( scope, { handle, answer }) {
|
|
1780
1816
|
/* Try to upload one or more files to a file-type input field.
|
package/lib/steps.js
CHANGED
|
@@ -203,6 +203,7 @@ Given(/I start the interview at "([^"]+)"/, {timeout: -1}, async (file_name) =>
|
|
|
203
203
|
// at any one time since each step completes synchronously
|
|
204
204
|
|
|
205
205
|
// If response has a file in it that matches the file we are downloading
|
|
206
|
+
// Sadly, 'content-disposition' isn't working. We're not sure what will.
|
|
206
207
|
if ( response.headers()['content-disposition'] && (response.headers()['content-disposition']).includes(`attachment;filename=${scope.toDownload}`) ) {
|
|
207
208
|
// We're choosing to avoid removing the event listener in case removal
|
|
208
209
|
// would prevent downloading other files. The listener should get
|