@suffolklitlab/alkiln 5.0.0-pre-7 → 5.0.0-pre-8
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 +2 -0
- package/lib/scope.js +94 -69
- package/lib/utils/langs.js +2 -2
- package/npm-shrinkwrap.json +1030 -531
- package/package.json +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -59,6 +59,8 @@ Format:
|
|
|
59
59
|
- Change interface for testing languages. See [#713](https://github.com/SuffolkLITLab/ALKiln/issues/713).
|
|
60
60
|
|
|
61
61
|
### Fixed
|
|
62
|
+
- DOCKER UPDATE (for ALKilnInThePlayground): Allows ALKilnInThePlayground to upload files. See https://github.com/SuffolkLITLab/docassemble-ALKilnInThePlayground/issues/18. This may require some developers to update their system (updating their docker image) if they are below [docassemble-os 1.0.8](https://github.com/jhpyle/docassemble-os/releases/tag/v1.0.8). You can tell if you are below docassemble-os 1.0.8 if you run `docker image inspect jhpyle/docassemble | grep Created` on your host server (Lightsail, etc.) and the created date is before 2023-04-09. You can update as described in [the documentation](https://suffolklitlab.org/legal-tech-class/docs/practical-guide-docassemble/maintaining-docassemble#updates-to-the-docassemble-container). Updating to a new docker images is something that all docassemble users will have to do sometime anyway, sometimes for security.
|
|
63
|
+
- Conform upload file behavior to that of other Story Table rows - avoid erroring when field isn't set properly unless using all variables is required.
|
|
62
64
|
- Projects created in da each have a unique name. https://github.com/SuffolkLITLab/ALKiln/issues/663
|
|
63
65
|
- Shorten path names to try to accommodate limitations of windows systems while still keeping enough useful information to help devs identify the test outputs. https://github.com/SuffolkLITLab/ALKiln/issues/618
|
|
64
66
|
- Updated field decoding to handle new object field encoding. See [#711](https://github.com/SuffolkLITLab/ALKiln/issues/711)
|
package/lib/scope.js
CHANGED
|
@@ -2,6 +2,7 @@ const { expect } = require('chai');
|
|
|
2
2
|
const cheerio = require('cheerio');
|
|
3
3
|
const path = require('path');
|
|
4
4
|
const fs = require('fs');
|
|
5
|
+
const fg = require('fast-glob');
|
|
5
6
|
const { AxePuppeteer } = require('@axe-core/puppeteer');
|
|
6
7
|
const safe_filename = require("sanitize-filename");
|
|
7
8
|
// "en" is faster to import: https://github.com/faker-js/faker/issues/1114#issuecomment-1169532948
|
|
@@ -1528,7 +1529,10 @@ module.exports = {
|
|
|
1528
1529
|
let row = matching_input_rows[ matching_input_rows.length - 1 ];
|
|
1529
1530
|
let answer = row.value;
|
|
1530
1531
|
|
|
1531
|
-
|
|
1532
|
+
// Will implement `was_used` in cases as they come along. For now, this is
|
|
1533
|
+
// necessary for file uploads to be as flexible as any other Story Table row.
|
|
1534
|
+
let was_used = await scope.funnel_the_answer( scope, { handle, answer, field });
|
|
1535
|
+
if ( was_used === false ) { row = null; }
|
|
1532
1536
|
|
|
1533
1537
|
return row;
|
|
1534
1538
|
}, // Ends scope.setVariable()
|
|
@@ -1590,16 +1594,18 @@ module.exports = {
|
|
|
1590
1594
|
custom_datatype = await scope.get_custom_datatype( scope, { handle });
|
|
1591
1595
|
}
|
|
1592
1596
|
|
|
1597
|
+
let row_was_used = true;
|
|
1593
1598
|
// If there is a custom datatype function available, use it to set the field
|
|
1594
1599
|
if ( scope.setCustomDatatype[ custom_datatype ] !== undefined ) {
|
|
1595
1600
|
// Set da package custom fields. TODO: find `custom_handle` in the setter?
|
|
1596
1601
|
let custom_handle = await handle.evaluateHandle(( elem )=> { return elem.closest( `.da-form-group` ) });
|
|
1597
|
-
await scope.setCustomDatatype[ custom_datatype ]( scope, { handle: custom_handle, answer });
|
|
1602
|
+
row_was_used = await scope.setCustomDatatype[ custom_datatype ]( scope, { handle: custom_handle, answer });
|
|
1598
1603
|
} else {
|
|
1599
1604
|
// If no custom datatype, set a regular field
|
|
1600
|
-
await scope.enter_answer[ field.tag ]( scope, { handle, answer });
|
|
1605
|
+
row_was_used = await scope.enter_answer[ field.tag ]( scope, { handle, answer });
|
|
1601
1606
|
}
|
|
1602
1607
|
|
|
1608
|
+
return row_was_used;
|
|
1603
1609
|
}, // Ends scope.funnel_the_answer()
|
|
1604
1610
|
|
|
1605
1611
|
// Handle setting values for da custom datatypes. E.g. `da-field-container-datatype-BirthDate`
|
|
@@ -1660,10 +1666,14 @@ module.exports = {
|
|
|
1660
1666
|
}, // ends setCustomDatatype {}
|
|
1661
1667
|
|
|
1662
1668
|
enter_answer: {
|
|
1663
|
-
button: async function ( scope, { handle, answer }) {
|
|
1669
|
+
button: async function ( scope, { handle, answer }) {
|
|
1670
|
+
await scope.tapElement( scope, handle );
|
|
1671
|
+
return true;
|
|
1672
|
+
},
|
|
1664
1673
|
textarea: async function ( scope, { handle, answer }) {
|
|
1665
1674
|
await scope.setText( scope, { handle, answer });
|
|
1666
1675
|
await scope.afterStep(scope); // No showifs for this one?
|
|
1676
|
+
return true;
|
|
1667
1677
|
},
|
|
1668
1678
|
select: async function ( scope, { handle, answer }) {
|
|
1669
1679
|
// Note: I don't remember what's really going on in here.
|
|
@@ -1692,13 +1702,16 @@ module.exports = {
|
|
|
1692
1702
|
}
|
|
1693
1703
|
|
|
1694
1704
|
await scope.afterStep(scope, { waitForShowIf: true });
|
|
1705
|
+
return true;
|
|
1695
1706
|
},
|
|
1696
1707
|
canvas: async function ( scope, { handle, answer }) {
|
|
1697
1708
|
await scope.draw_signature( scope );
|
|
1698
1709
|
await scope.afterStep( scope );
|
|
1710
|
+
return true;
|
|
1699
1711
|
},
|
|
1700
1712
|
input: async function ( scope, { handle, answer }) {
|
|
1701
1713
|
/* Set value of some `input` element to the given value. */
|
|
1714
|
+
let row_was_used = true;
|
|
1702
1715
|
|
|
1703
1716
|
let type = await handle.evaluate( elem => { return elem.getAttribute('type'); });
|
|
1704
1717
|
if ( type === `radio` || type === `checkbox` ) {
|
|
@@ -1717,7 +1730,7 @@ module.exports = {
|
|
|
1717
1730
|
await scope.afterStep(scope, { waitForShowIf: true });
|
|
1718
1731
|
|
|
1719
1732
|
} else if ( type === `file` ) {
|
|
1720
|
-
await scope.uploadFiles( scope, { handle, answer });
|
|
1733
|
+
row_was_used = await scope.uploadFiles( scope, { handle, answer });
|
|
1721
1734
|
await scope.afterStep(scope, { waitForShowIf: true });
|
|
1722
1735
|
|
|
1723
1736
|
} else if (type == `date`) {
|
|
@@ -1746,6 +1759,8 @@ module.exports = {
|
|
|
1746
1759
|
await scope.setText( scope, { handle, answer });
|
|
1747
1760
|
await scope.afterStep(scope, { waitForShowIf: true });
|
|
1748
1761
|
}
|
|
1762
|
+
|
|
1763
|
+
return row_was_used;
|
|
1749
1764
|
}, // Ends scope.enter_answer.input()
|
|
1750
1765
|
hidden: async function ( scope, { handle, answer }) {
|
|
1751
1766
|
// Do nothing. The only way the code should get here is if
|
|
@@ -1762,89 +1777,98 @@ module.exports = {
|
|
|
1762
1777
|
uploadFiles: async function ( scope, { handle, answer }) {
|
|
1763
1778
|
/* Try to upload one or more files to a file-type input field.
|
|
1764
1779
|
* Does not submit, so no danger of timeout with server reload.
|
|
1780
|
+
*
|
|
1781
|
+
* Returns whether the row was used or not.
|
|
1765
1782
|
*/
|
|
1766
1783
|
|
|
1767
|
-
//
|
|
1768
|
-
//
|
|
1769
|
-
let
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
if (dirs.length < 1) {
|
|
1777
|
-
let msg = `You can store files to upload in 'docassemble/${ subpackage_name }/data/source'. These tests could not find a folder like that starting at ${ process.cwd() }.`;
|
|
1778
|
-
await scope.addToReport( scope, { type: `warning`, value: msg});
|
|
1779
|
-
throw Error(msg); // Most people will want to know the sources folder path;
|
|
1780
|
-
}
|
|
1781
|
-
for (let dir of dirs) {
|
|
1782
|
-
pkg_paths.push(`${docassemble_pkg_path}/${dir}`);
|
|
1783
|
-
}
|
|
1784
|
-
} catch ( error_da ) {
|
|
1785
|
-
let msg = `You can store files to upload in 'docassemble/${ subpackage_name }/data/source'. ` +
|
|
1786
|
-
`These tests could not find a folder like that. The current directory is ` +
|
|
1787
|
-
` ${ process.cwd() }; is that in the top level folder of your docassemble package? (${ session_vars.get_package_name() })?`;
|
|
1788
|
-
await scope.addToReport( scope, { type: `warning`, value: msg});
|
|
1789
|
-
throw error_da; // Most people will want to know the sources folder path;
|
|
1784
|
+
// First make sure the list of files was defined. Don't remove spaces yet -
|
|
1785
|
+
// allow a typo where someone forgot to include a space after a comma.
|
|
1786
|
+
let uploads_names = answer.split(`,`);
|
|
1787
|
+
if ( uploads_names.length === 0 ) {
|
|
1788
|
+
await scope.addToReport( scope, {
|
|
1789
|
+
type: `error`,
|
|
1790
|
+
value: `Your list of files to upload is empty.`
|
|
1791
|
+
});
|
|
1792
|
+
return false; // The row wasn't used
|
|
1790
1793
|
}
|
|
1791
1794
|
|
|
1792
|
-
let
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1795
|
+
let dirs = [];
|
|
1796
|
+
if ( session_vars.get_origin() === `playground` ) {
|
|
1797
|
+
let files_playground = fg.sync(
|
|
1798
|
+
[ `/usr/share/docassemble/files/playgroundsources/${session_vars.get_user_id()}/${session_vars.get_user_project_name()}` ],
|
|
1799
|
+
{ onlyFiles: false, suppressErrors: true }
|
|
1800
|
+
);
|
|
1801
|
+
let files_s3 = fg.sync(
|
|
1802
|
+
[ `/tmp/playgroundsources/${session_vars.get_user_id()}/${session_vars.get_user_project_name()}` ],
|
|
1803
|
+
{ onlyFiles: false, suppressErrors: true }
|
|
1804
|
+
);
|
|
1805
|
+
|
|
1806
|
+
dirs = files_playground.concat( files_s3 );
|
|
1807
|
+
} else {
|
|
1808
|
+
dirs = fg.sync(
|
|
1809
|
+
[ `**/docassemble/**/data/sources` ],
|
|
1810
|
+
{ onlyFiles: false, suppressErrors: true }
|
|
1811
|
+
);
|
|
1808
1812
|
}
|
|
1809
1813
|
|
|
1810
|
-
if (
|
|
1811
|
-
|
|
1814
|
+
if ( session_vars.get_debug() ) {
|
|
1815
|
+
console.log( `All discovered dirs to upload from:`, dirs );
|
|
1812
1816
|
}
|
|
1813
1817
|
|
|
1814
|
-
//
|
|
1815
|
-
|
|
1818
|
+
// Make sure sources directory exists and has files in it
|
|
1819
|
+
if ( dirs.length === 0 ) {
|
|
1820
|
+
await scope.addToReport( scope, {
|
|
1821
|
+
type: `warning`,
|
|
1822
|
+
value: `The test files need to be in the "sources" directory, `
|
|
1823
|
+
+ `but ALKiln couldn't find the directory or it was empty.`
|
|
1824
|
+
});
|
|
1825
|
+
return false; // The row wasn't used
|
|
1826
|
+
}
|
|
1816
1827
|
|
|
1817
|
-
//
|
|
1828
|
+
// Get the full paths of all the files
|
|
1829
|
+
let dir = null;
|
|
1818
1830
|
let paths = [];
|
|
1819
|
-
|
|
1831
|
+
let missing_files = []; // For any user warnings
|
|
1832
|
+
for ( let name of uploads_names ) {
|
|
1833
|
+
|
|
1834
|
+
let trimmed_name = name.trim();
|
|
1835
|
+
let matching_paths = [];
|
|
1836
|
+
|
|
1837
|
+
for ( let one_dir of dirs ) {
|
|
1838
|
+
// accumulate all matching paths
|
|
1839
|
+
let new_paths = fg.sync([ `${ one_dir }/${ trimmed_name }` ]);
|
|
1840
|
+
matching_paths.push( ...new_paths );
|
|
1841
|
+
} // ends for each dir
|
|
1842
|
+
|
|
1843
|
+
if ( matching_paths.length === 0 ) {
|
|
1844
|
+
missing_files.push( trimmed_name );
|
|
1845
|
+
} else {
|
|
1846
|
+
paths.push( ...matching_paths );
|
|
1847
|
+
}
|
|
1820
1848
|
|
|
1821
|
-
|
|
1822
|
-
// start of the string. Remove it. If they forgot the space, that's fine too.
|
|
1823
|
-
name = name.replace(/^\s/, '');
|
|
1824
|
-
let file_path = path.join( chosen_dir, name );
|
|
1849
|
+
} // ends for each file
|
|
1825
1850
|
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1851
|
+
if ( missing_files.length > 0 ) {
|
|
1852
|
+
await scope.addToReport( scope, {
|
|
1853
|
+
type: `warning`,
|
|
1854
|
+
value: `ALKiln could not find "${ missing_files.join('", "') }" in any of these folders: "${ dirs.join('", "') }".`
|
|
1855
|
+
});
|
|
1856
|
+
}
|
|
1857
|
+
|
|
1858
|
+
// If all files missing, return that the row wasn't used
|
|
1859
|
+
if ( missing_files.length === uploads_names.length ) {
|
|
1860
|
+
return false; // The row wasn't used
|
|
1833
1861
|
}
|
|
1834
1862
|
|
|
1835
|
-
if ( paths.length === 0 ) {
|
|
1836
|
-
await scope.addToReport( scope, { type: `error`, value: `Could not find "${answer}".` });
|
|
1837
|
-
throw ReferenceError(`Could not find "${answer}".`)
|
|
1838
|
-
}
|
|
1839
1863
|
// Prepare to wait for upload to complete
|
|
1840
1864
|
let name = await handle.evaluate( elem => { return elem.getAttribute(`name`); });
|
|
1841
1865
|
let selector = `*[name="${ name }"]`
|
|
1842
1866
|
let disabled_selector = `${ selector }[disabled]`;
|
|
1843
1867
|
let enabled_selector = `${ selector }:not([disabled])`;
|
|
1844
1868
|
|
|
1845
|
-
// This comes before the upload starts
|
|
1846
|
-
// Notice `await` is absent. Don't actually wait here.
|
|
1847
|
-
//
|
|
1869
|
+
// This comes before the upload starts.
|
|
1870
|
+
// Notice `await` is absent. Don't actually wait here yet.
|
|
1871
|
+
// Start looking for it before it exists or we might miss it.
|
|
1848
1872
|
let wait_for_disable = scope.page.waitForSelector( disabled_selector );
|
|
1849
1873
|
|
|
1850
1874
|
// Upload
|
|
@@ -1855,8 +1879,9 @@ module.exports = {
|
|
|
1855
1879
|
await wait_for_disable;
|
|
1856
1880
|
// When it's again enabled, the files have finished loading. Or so I have observed.
|
|
1857
1881
|
await scope.page.waitForSelector( enabled_selector );
|
|
1858
|
-
|
|
1859
1882
|
|
|
1883
|
+
// Return that the row was used
|
|
1884
|
+
return true;
|
|
1860
1885
|
}, // Ends scope.uploadFiles()
|
|
1861
1886
|
|
|
1862
1887
|
setCheckbox: async function ( scope, { label, answer }) {
|
package/lib/utils/langs.js
CHANGED
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
let _path = require('path');
|
|
4
4
|
let fs = require('fs');
|
|
5
|
-
|
|
5
|
+
const fg = require('fast-glob');
|
|
6
6
|
|
|
7
7
|
let session_vars = require('./session_vars');
|
|
8
8
|
|
|
9
9
|
// Get the glob filepaths to find all the test files
|
|
10
10
|
let dir_root = process.env.INIT_CWD; // Path to root of project
|
|
11
11
|
let test_glob = process.argv[2]; // String of glob (regex for filepaths)
|
|
12
|
-
let filepaths =
|
|
12
|
+
let filepaths = fg.sync( _path.resolve( dir_root, test_glob ) );
|
|
13
13
|
let flag = '_lang_';
|
|
14
14
|
|
|
15
15
|
let langs = session_vars.get_languages();
|