@suffolklitlab/alkiln 5.13.1 → 5.13.2

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.
@@ -52,8 +52,8 @@ jobs:
52
52
  EMPTY_STRING: ""
53
53
  NORMAL_USER_EMAIL: alkiln@example.com
54
54
  NORMAL_USER_PASSWORD: User123^
55
- WRONG_EMAIL=wrong_email@example.com
56
- WRONG_PASSWORD=wrong_password
55
+ WRONG_EMAIL: wrong_email@example.com
56
+ WRONG_PASSWORD: wrong_password
57
57
 
58
58
  steps:
59
59
  # Place the root directory in this branch to access
@@ -160,7 +160,7 @@ jobs:
160
160
  #### Developer note: You can probably leave the rest out
161
161
  #### To learn more, see https://assemblyline.suffolklitlab.org/docs/alkiln/writing/#optional-inputs
162
162
  ALKILN_TAG_EXPRESSION: "${{ env.ALKILN_TAG_EXPRESSION }}"
163
- ALKILN_VERSION: delete
163
+ ALKILN_VERSION: download
164
164
 
165
165
  #### Developer note: Example of making an issue when tests fail
166
166
  #### that includes the text of the failure output file
@@ -47,8 +47,8 @@ jobs:
47
47
  NORMAL_USER_PASSWORD: ${{ secrets.USER_NO_PERMISSIONS_PASSWORD }}
48
48
  NORMAL_USER_API_KEY: ${{ secrets.USER_NO_PERMISSIONS_API_KEY }}
49
49
  INVALID_API_KEY: invalidAPIkey
50
- WRONG_EMAIL=wrong_email@example.com
51
- WRONG_PASSWORD=wrong_password
50
+ WRONG_EMAIL: wrong_email@example.com
51
+ WRONG_PASSWORD: wrong_password
52
52
  EMPTY_STRING: ""
53
53
  SECRET_VAR1: secret-var1-value
54
54
  SECRET_VAR2: secret-var2-value
@@ -81,4 +81,4 @@ jobs:
81
81
  # want to check up on this.
82
82
  ALKILN_TAG_EXPRESSION: "${{ env.ALKILN_TAG_EXPRESSION }}"
83
83
  #### Developer note: You can probably leave this out
84
- ALKILN_VERSION: delete
84
+ ALKILN_VERSION: download
package/CHANGELOG.md CHANGED
@@ -45,6 +45,13 @@ Format:
45
45
 
46
46
  ## [Unreleased]
47
47
 
48
+ ## [5.13.2] - 2024-11-23
49
+
50
+ ### Fixed
51
+ - Fixes download Step unable to use a partial filename match. The Step needed the whole name, including the extension. See [#725](https://github.com/SuffolkLITLab/ALKiln/issues/725).
52
+
53
+ ## [5.13.1] - 2024-10-23
54
+
48
55
  ### Changed
49
56
 
50
57
  - Moves "expected" status error to only be visible to internal test errors. Closes [#933](https://github.com/SuffolkLITLab/ALKiln/issues/933).
@@ -52,7 +59,6 @@ Format:
52
59
  ### Fixed
53
60
 
54
61
  - Detects failed sign in. Closes [#918](https://github.com/SuffolkLITLab/ALKiln/issues/918).
55
- - Updates pdfjs-dist for node v20 and v22. See [#952](https://github.com/SuffolkLITLab/ALKiln/issues/952).
56
62
 
57
63
  ### Internal
58
64
 
@@ -63,6 +69,7 @@ Format:
63
69
  - Adds decision docs
64
70
  - Updated CONTRIBUTING.md
65
71
  - Added example.env, closes [#374](https://github.com/SuffolkLITLab/ALKiln/issues/374)
72
+ - Updates pdfjs-dist for node v20 and v22. See [#952](https://github.com/SuffolkLITLab/ALKiln/issues/952).
66
73
 
67
74
  ## [5.13.0] - 2024-07-11
68
75
 
package/README.md CHANGED
@@ -41,25 +41,46 @@ Read about contributing in our [CONTRIBUTING.md document](CONTRIBUTING.md). Here
41
41
  ## Cheat sheet
42
42
 
43
43
  *Once you've already read the contributing documentation, you can use these as quick reminders for running our internal tests.*
44
- To set up for the integration tests, create the project on the server:
44
+
45
+ ### `setup` before starting development of a feature/fix
46
+
47
+ Set up for the cucumber integration tests.
48
+
49
+ Add the feature branch name to your `.env` file:
50
+
51
+ ```
52
+ BRANCH=42_feat_life_the_univers_and_everything
53
+ ```
54
+
55
+ Then create the project on the server:
45
56
 
46
57
  ```bash
47
58
  npm run setup
48
59
  ```
49
60
 
50
- Use the syntax below to trigger specific tags:
61
+ ### Run tests repeatedly
62
+
63
+ Run all cucumber tests that are not currently blocked by upstream changes:
64
+
65
+ ```bash
66
+ npm run pass
67
+ ```
68
+
69
+ Trigger cucumber tests with specific tags:
51
70
 
52
71
  ```bash
53
- npm run cucumber -- "--tags" "@tagname"
72
+ npm run cucumber "@tagname"
54
73
  ```
55
74
 
56
- To run the unit tests in isolation:
75
+ Run the unit tests:
57
76
 
58
77
  ```bash
59
78
  npm run unit
60
79
  ```
61
80
 
62
- If you or someone else changes the interview code in `./docassemble`, you have to clean up the old data on the server before running `setup` again:
81
+ ### Always run `takedown` before running `setup` again
82
+
83
+ If you or someone else changes the interview code in our `./docassemble` directory, you have to delete the code currently on the testing server before running `setup` again. Also do this when you're done with the feature/fix or starting a new feature/fix.
63
84
 
64
85
  ```bash
65
86
  npm run takedown
package/lib/scope.js CHANGED
@@ -2781,7 +2781,7 @@ module.exports = {
2781
2781
  await scope.afterStep(scope);
2782
2782
  }, // Ends scope.steps.sign()
2783
2783
 
2784
- download: async ( scope, filename ) => {
2784
+ download: async ( scope, full_or_partial_file_href ) => {
2785
2785
  /* Taps the link that leads to the given filename to trigger downloading.
2786
2786
  * and waits till the file has been downloaded before allowing the tests to continue.
2787
2787
  * WARNING: Cannot download the same file twice in a single scenario.
@@ -2791,47 +2791,86 @@ module.exports = {
2791
2791
  * TODO: Properly wait for download to complete. See notes in
2792
2792
  * scope.js scope.detectDownloadComplete()
2793
2793
  */
2794
- let [elem] = await scope.page.$$(`xpath/.//a[contains(@href, "${ filename }")]`);
2794
+ let [elem] = await scope.page.$$(`xpath/.//a[contains(@href, "${ full_or_partial_file_href }")]`);
2795
2795
 
2796
- let msg = `"${ filename }" seems to be missing. Cannot find a link to that document.`;
2796
+ let msg = `"${ full_or_partial_file_href }" seems to be missing on the page. Cannot find a link to that document.`;
2797
2797
  if ( !elem ) { reports.addToReport(scope, { type: `error`, code: `ALK0152`, value: msg }); }
2798
2798
  expect( elem, msg ).to.exist;
2799
2799
 
2800
2800
  let failed_to_download = false;
2801
2801
  let err_msg = "";
2802
2802
  try {
2803
- const binaryStr = await scope.page.evaluate(el => {
2803
+
2804
+ const { disposition, binaryStr } = await scope.page.evaluate(async function ( el ) {
2804
2805
  const url = el.getAttribute("href");
2805
2806
  return new Promise(async (resolve, reject) => {
2806
2807
  const response = await fetch(url, {method: "GET"});
2807
2808
  const reader = new FileReader();
2808
2809
  reader.readAsBinaryString(await response.blob());
2809
- reader.onload = () => resolve(reader.result);
2810
+ // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition
2811
+ reader.onload = () => resolve({
2812
+ disposition: response.headers.get(`Content-Disposition`),
2813
+ binaryStr: reader.result
2814
+ });
2810
2815
  reader.onerror = () => reject(`šŸ¤• ALK0153 ERROR: Error occurred on page when downloading ${ url }: ${ reader.error }`);
2811
2816
  });
2812
2817
  }, elem);
2818
+
2819
+ err_msg = `could not get the actual name of the file from the response headers.`;
2820
+ let actual_filename = await scope.steps.get_response_filename({
2821
+ disposition, default_name: full_or_partial_file_href
2822
+ });
2823
+
2813
2824
  if (binaryStr !== '') {
2825
+ err_msg = `binary data for download was empty`;
2814
2826
  const fileData = Buffer.from(binaryStr, 'binary');
2815
- fs.writeFileSync(`${ scope.paths.scenario }/${ filename }`, fileData);
2816
- reports.addToReport(scope, { type: `row info`, code: `ALK0154`, value: `Downloaded ${ filename } (${ fileData.length } bytes) to ${ scope.paths.scenario }`});
2827
+ fs.writeFileSync(`${ scope.paths.scenario }/${ actual_filename }`, fileData);
2828
+ reports.addToReport(scope, { type: `row info`, code: `ALK0154`, value: `Downloaded "${ actual_filename }" (${ fileData.length } bytes) to ${ scope.paths.scenario }`});
2817
2829
  } else {
2818
2830
  failed_to_download = true;
2819
- err_msg = `Couldn't download ${ filename }, binary data for download was empty`;
2820
2831
  }
2832
+
2821
2833
  } catch (error) {
2822
2834
  failed_to_download = true;
2823
2835
  err_msg = error;
2824
2836
  }
2825
2837
 
2826
2838
  if (failed_to_download) {
2827
- reports.addToReport(scope, { type: `warning`, code: `ALK0155`, value: `Could not download file using fetch (${ err_msg }). ALKiln will now fallback to the click download method.` });
2828
- scope.toDownload = filename;
2839
+ reports.addToReport(scope, { type: `warning`, code: `ALK0155`, value: `Could not download a file matching the name "${ full_or_partial_file_href }" using fetch (${ err_msg }). ALKiln will now fallback to the click download method.` });
2840
+ scope.toDownload = full_or_partial_file_href;
2829
2841
  // Should this be using `scope.tapElement`?
2830
2842
  await elem.evaluate( elem => { return elem.click(); });
2831
2843
  await scope.detectDownloadComplete( scope );
2832
2844
  }
2833
2845
  }, // Ends scope.steps.download()
2834
2846
 
2847
+ get_response_filename: async function({ disposition, default_name=`found_no_file_name.pdf` }) {
2848
+ /** Given a fetch response headers' Content-Disposition str, return the
2849
+ * filename of the response's file.
2850
+ *
2851
+ * @return { string | null } - Name of fetched file
2852
+ * */
2853
+ let filename = default_name;
2854
+ if ( disposition ) {
2855
+ filename = disposition.split(`;`)[1].split(`=`)[1];
2856
+ }
2857
+
2858
+ // Handle potential UTF-8 encoded filenames
2859
+ if ( filename.toLowerCase().startsWith( `utf-8''` )) {
2860
+ filename = decodeURIComponent( filename.replace( /utf-8''/i, `` ));
2861
+ } else {
2862
+ // Replace starting and ending quotes if they exist
2863
+ filename = filename.replace( /^['"]/, `` ).replace( /['"]$/, `` );
2864
+ }
2865
+
2866
+ // TODO: Add debug log here
2867
+ // console.log(`filename:`, filename);
2868
+
2869
+ // TODO: Add to the report if we had to use the default name
2870
+
2871
+ return filename;
2872
+ }, // Ends scope.steps.get_response_filename()
2873
+
2835
2874
  compare_pdfs: async function (scope, {existing_pdf_path, new_pdf_path}) {
2836
2875
  let existing_paths = await scope.findFiles(scope, {to_find_names: [existing_pdf_path]});
2837
2876
  if (existing_paths.length == 0) {
@@ -2852,7 +2891,7 @@ module.exports = {
2852
2891
  let removed_str = diffs.filter(part => part.removed).reduce((err_str, part) => {
2853
2892
  return err_str + `- ${ part.value }\n`
2854
2893
  }, 'The new PDF removed: \n');
2855
- let msg = `The PDFs were not the same.\n${ added_str }\n${removed_str}\n\n You can see the full PDFs at ${ full_existing_path } and ${ full_new_pdf_path}`;
2894
+ let msg = `The PDFs were different.\nAdded:\n${ added_str }\nRemoved:\n${removed_str}\n\nThere might be more information if you actually look at the files. You can see the full PDFs at ${ full_existing_path } and ${ full_new_pdf_path}`;
2856
2895
  reports.addToReport(scope, { type: `error`, code: `ALK0157`, value: msg });
2857
2896
  scope.failed_pdf_compares.push(msg);
2858
2897
  }
package/lib/steps.js CHANGED
@@ -1285,10 +1285,11 @@ After(async function(scenario) {
1285
1285
  if ( scope.failed_pdf_compares.length > 0) {
1286
1286
  let msg = scope.failed_pdf_compares.reduce((str, new_msg) => `${ str }\n―――\n${ new_msg }`)
1287
1287
  changeable_test_status = `FAILED`;
1288
+ // TODO: This may be redundant and therefore confusing
1288
1289
  reports.addToReport(scope, {
1289
1290
  type: `error`,
1290
1291
  code: `ALK0093`,
1291
- value: `PDF comparison failed ${ scope.failed_pdf_compares.length } time(s)\n―――\n${ msg }\n―――\n`
1292
+ value: `ALKiln ran into an error when it tried to compare ${ scope.failed_pdf_compares.length } PDF(s)\n―――\n${ msg }\n―――\n`
1292
1293
  });
1293
1294
  }
1294
1295
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@suffolklitlab/alkiln",
3
- "version": "5.13.1",
3
+ "version": "5.13.2",
4
4
  "description": "Integrated automated end-to-end testing with docassemble, puppeteer, and cucumber.",
5
5
  "main": "lib/index.js",
6
6
  "scripts": {