Should I test the whole repo when editing one package? Some tests already failing

Lets say I made an edit to some file inside package/lib, before opening a PR, do I have to run yarn test at the root of the repo and test all the application, or is running yarn test for only lib package enough?

I'm asking because right now I've forked the whole project and tried to do yarn test, multiple tests failed in various package and I haven't yet changed a thing, so I'm not sure what's the testing strategy when I make changes, given that already multiple tests fail so I may not know whether it is due to my changes or from before?

Edit: Well it's basically 2 questions in the same thread, sorry if that is not allowed

1 Like

Joplin's CI runs yarn test from the root of the repository on both Linux and MacOS. As such, it shouldn't be necessary to run all tests locally before creating a pull request.

I do suggest running the tests related to any changes you make before submitting a pull request though.

so I'm not sure what's the testing strategy when I make changes, given that already multiple tests fail so I may not know whether it is due to my changes or from before?

Which tests are failing? Which platform are you running the tests on?

Node version 20.11.0
Windows 10
dev branch

Some tests from multiple packages failed. The following is a sample from running test on package/lib:

FAIL  services/rest/routes/events.test.js (136.299 s)
  ● routes/events › should limit the number of response items

    thrown: "Exceeded timeout of 90000 ms for a test.
    Add a timeout value to this test to increase the timeout, if this is a long-running test. See https://jestjs.io/docs/api#testname-fn-timeout."

      57 |      });
      58 |
    > 59 |      it('should limit the number of response items', async () => {
         |      ^
      60 |              const promises = [];
      61 |              for (let i = 0; i < 101; i++) {
      62 |                      promises.push(Note.save({ title: 'toto' }));

      at it (services/rest/routes/events.test.ts:59:2)
      at Object.describe (services/rest/routes/events.test.ts:10:1)

A worker process has failed to exit gracefully and has been force exited. This is likely caused by tests leaking due to improper teardown. Try running with --detectOpenHandles to find leaks. Active timers can also cause this, ensure that .unref() was called on them.
Summary of all failing tests
 FAIL  services/RevisionService.test.js (193.728 s)
  ● services/RevisionService › should not create a revision if there is already a recent one

    expect(received).toBe(expected) // Object.is equality

    Expected: true
    Received: false

      470 |             await Note.save({ id: n1_v0.id, title: 'hello 3' });
      471 |             await revisionService().collectRevisions(); // No rev because time since last rev is less than the required 'interval between revisions'
    > 472 |             expect(Date.now() - interval < timeRev2).toBe(true); // check the computer is not too slow for this test
          |                                                      ^
      473 |             expect((await Revision.all()).length).toBe(2);
      474 |     }));
      475 |

      at toBe (services/RevisionService.test.ts:472:44)
      at fulfilled (services/RevisionService.test.js:12:24)

 FAIL  services/rest/Api.test.js (256.942 s)
  ● services_rest_Api › should create notes with pdf embeds

    expect(received).toBe(expected) // Object.is equality

    Expected: true
    Received: false

      518 |
      519 |             const resource = resources[0];
    > 520 |             expect(response.body.indexOf(resource.id) >= 0).toBe(true);
          |                                                             ^
      521 |     }));
      522 |
      523 |     it('should handle tokens', (async () => {

      at toBe (services/rest/Api.test.ts:520:51)
      at fulfilled (services/rest/Api.test.js:12:24)

 FAIL  ./import-enex-md-gen.test.js (117.903 s)
  ● import-enex-md-gen › should convert ENEX content to Markdown

    expect(received).toBe(expected) // Object.is equality

    Expected: true
    Received: false

      67 |                              console.info(result.join('\n'));
      68 |
    > 69 |                              expect(false).toBe(true);
         |                                            ^
      70 |                              // return;
      71 |                      } else {
      72 |                              expect(true).toBe(true);

      at toBe (import-enex-md-gen.test.ts:69:19)
      at fulfilled (import-enex-md-gen.test.js:12:24)

  ● import-enex-md-gen › should handle tasks

    expect(received).toEqual(expected) // deep equality

    - Expected  - 11
    + Received  + 11

    - a
    - 
    - b
    - 
    + a
    +
    + b
    +
    - List 1
    - 
    + List 1
    +
    - - [x] Clara
    + - [x] Clara
    - - [ ] Bob
    - 
    + - [ ] Bob
    +
    - List 2
    - 
    + List 2
    +
      - [ ] Jeff

      119 |             const expectedMd = await shim.fsDriver().readFile(`${enexSampleBaseDir}/tasks.md`);
      120 |             const note: NoteEntity = (await Note.all())[0];
    > 121 |             expect(note.body).toEqual(expectedMd);
          |                               ^
      122 |     });
      123 |
      124 |     it('should handle empty note content', async () => {

      at toEqual (import-enex-md-gen.test.ts:121:21)
      at fulfilled (import-enex-md-gen.test.js:12:24)

  ● import-enex-md-gen › should import images with sizes

    expect(received).toBe(expected) // Object.is equality

    - Expected  - 16
    + Received  + 16

    - ![](:/52de02640b588b40dcb0a920b9e089bb)
    - 
    + ![](:/52de02640b588b40dcb0a920b9e089bb)
    +
    - #### Last Transfer
    - 
    + #### Last Transfer
    +
    - <img src=":/b3d82d4e0af0fe302ee3e2339edfe13d" width="65" height="65" alt="bank.svg"/>
    - 
    + <img src=":/b3d82d4e0af0fe302ee3e2339edfe13d" width="65" height="65" alt="bank.svg"/>
    +
    - ##### **Next Day Bank Deposit / USD**
    - 
    + ##### **Next Day Bank Deposit / USD**
    +
    - ###### **March 5, 2023 04:28AM**
    - 
    + ###### **March 5, 2023 04:28AM**
    +
    - * * *
    - 
    + * * *
    +
    - Processing
    + Processing
    - **Confirmation**: ILbwHO5Z06p7meW
    - 
    + **Confirmation**: ILbwHO5Z06p7meW
    +
    - ![](https://joplinapp.org/images/logo-text.svg)
    + ![](https://joplinapp.org/images/logo-text.svg)
      <img src="https://joplinapp.org/images/logo-text.svg" width="100" height="50"/>

      186 |             expected = expected.replace(/RESOURCE_ID_2/, svgResource.id);
      187 |
    > 188 |             expect(note.body).toBe(expected);
          |                               ^
      189 |             const filePath = `${enexSampleBaseDir}/invalid_html.enex`;
      190 |             await expectThrow(async () => importEnex('', filePath));
      191 |     });

      at toBe (import-enex-md-gen.test.ts:188:21)
      at fulfilled (import-enex-md-gen.test.js:12:24)

 FAIL  services/interop/InteropService_Importer_Md_frontmatter.test.js (146.477 s)
  ● InteropService_Importer_Md_frontmatter: importMetadata › should import file and set all metadata correctly

    expect(received).toBe(expected) // Object.is equality

    - Expected  - 1
    + Received  + 1

    - This is the note body
    + This is the note body
      ↵

      47 |              expect(note.todo_completed).toBe(0);
      48 |              expect(time.formatMsToLocal(note.todo_due, format)).toBe('22/08/2021 00:00');
    > 49 |              expect(note.body).toBe('This is the note body\n');
         |                                ^
      50 |
      51 |              const tags = await Tag.tagsByNoteId(note.id);
      52 |              expect(tags.length).toBe(3);

      at toBe (services/interop/InteropService_Importer_Md_frontmatter.test.ts:49:21)
      at fulfilled (services/interop/InteropService_Importer_Md_frontmatter.test.js:12:24)

  ● InteropService_Importer_Md_frontmatter: importMetadata › should only import data from the first yaml block

    expect(received).toBe(expected) // Object.is equality

    - Expected  - 5
    + Received  + 5

    - ---
    + ---
    - author: xxx
    + author: xxx
    - ---
    -
    + ---
    + 
    - note body
    + note body
      ↵

      62 |              expect(note.title).toBe('xxx');
      63 |              expect(note.author).not.toBe('xxx');
    > 64 |              expect(note.body).toBe('---\nauthor: xxx\n---\n\nnote body\n');
         |                                ^
      65 |      });
      66 |      it('should only import, duplicate notes and tags are not created', async () => {
      67 |              const note = await importTestFile('duplicates.md');

      at toBe (services/interop/InteropService_Importer_Md_frontmatter.test.ts:64:21)
      at fulfilled (services/interop/InteropService_Importer_Md_frontmatter.test.js:12:24)

  ● InteropService_Importer_Md_frontmatter: importMetadata › should not import items as numbers

    expect(received).toBe(expected) // Object.is equality

    - Expected  - 1
    + Received  + 1

    - note body
    + note body
      ↵

      78 |
      79 |              expect(note.title).toBe('001');
    > 80 |              expect(note.body).toBe('note body\n');
         |                                ^
      81 |      });
      82 |      it('should normalize whitespace and load correctly', async () => {
      83 |              const note = await importTestFile('normalize.md');

      at toBe (services/interop/InteropService_Importer_Md_frontmatter.test.ts:80:21)
      at fulfilled (services/interop/InteropService_Importer_Md_frontmatter.test.js:12:24)

  ● InteropService_Importer_Md_frontmatter: importMetadata › should normalize whitespace and load correctly

    expect(received).toBe(expected) // Object.is equality

    - Expected  - 1
    + Received  + 1

    - note body
    + note body
      ↵

      84 |
      85 |              expect(note.title).toBe('norm');
    > 86 |              expect(note.body).toBe('note body\n');
         |                                ^
      87 |
      88 |              const tags = await Tag.tagsByNoteId(note.id);
      89 |              expect(tags.length).toBe(3);

      at toBe (services/interop/InteropService_Importer_Md_frontmatter.test.ts:86:21)
      at fulfilled (services/interop/InteropService_Importer_Md_frontmatter.test.js:12:24)

  ● InteropService_Importer_Md_frontmatter: importMetadata › should load unquoted special forms correctly

    expect(received).toBe(expected) // Object.is equality

    - Expected  - 1
    + Received  + 1

    - note body
    + note body
      ↵

      93 |
      94 |              expect(note.title).toBe('Unquoted');
    > 95 |              expect(note.body).toBe('note body\n');
         |                                ^
      96 |
      97 |              expect(note.longitude).toBe('-94.51350100');
      98 |              expect(note.is_todo).toBe(1);

      at toBe (services/interop/InteropService_Importer_Md_frontmatter.test.ts:95:21)
      at fulfilled (services/interop/InteropService_Importer_Md_frontmatter.test.js:12:24)

  ● InteropService_Importer_Md_frontmatter: importMetadata › should accept file with no newline after the block marker

    expect(received).toBe(expected) // Object.is equality

    - Expected  - 1
    + Received  + 1

    - note body
    + note body
      ↵

      157 |     it('should accept file with no newline after the block marker', async () => {
      158 |             const note = await importTestFile('no_newline_after_marker.md');
    > 159 |             expect(note.body).toBe('note body\n');
          |                               ^
      160 |     });
      161 |
      162 |     it('should handle multiple newlines before the note body', async () => {

      at toBe (services/interop/InteropService_Importer_Md_frontmatter.test.ts:159:21)
      at fulfilled (services/interop/InteropService_Importer_Md_frontmatter.test.js:12:24)

  ● InteropService_Importer_Md_frontmatter: importMetadata › should handle multiple newlines before the note body

    expect(received).toBe(expected) // Object.is equality

    - Expected  - 2
    + Received  + 2

    -
    -
    + 
    + 
      note body

      162 |     it('should handle multiple newlines before the note body', async () => {
      163 |             const note = await importTestFile('multiple_newlines_after_marker.md');
    > 164 |             expect(note.body).toBe('\n\nnote body');
          |                               ^
      165 |     });
      166 |
      167 |     it('should accept note with a title that starts with a dash', async () => {

      at toBe (services/interop/InteropService_Importer_Md_frontmatter.test.ts:164:21)
      at fulfilled (services/interop/InteropService_Importer_Md_frontmatter.test.js:12:24)

  ● InteropService_Importer_Md_frontmatter: importMetadata › should recognize frontmatter in a file that starts with a UTF8 byte order mark

    expect(received).toBe(expected) // Object.is equality

    - Expected  - 1
    + Received  + 1

    - This note begins with an invisible byte order mark, just before its frontmatter.
    + This note begins with an invisible byte order mark, just before its frontmatter.
      ↵

      180 |             const note = await importTestFile('note_with_byte_order_mark.md');
      181 |             expect(note.title).toBe('Frontmatter test');
    > 182 |             expect(note.body).toBe('This note begins with an invisible byte order mark, just before its frontmatter.\n');     
          |                               ^
      183 |
      184 |             const tags = (await Tag.tagsByNoteId(note.id)).map(tag => tag.title).sort();
      185 |             expect(tags).toMatchObject(['tag1', 'tag2']);

      at toBe (services/interop/InteropService_Importer_Md_frontmatter.test.ts:182:21)
      at fulfilled (services/interop/InteropService_Importer_Md_frontmatter.test.js:12:24)

 FAIL  services/synchronizer/synchronizer_MigrationHandler.test.js (228.705 s)
  ● MigrationHandler › should apply migration 3 normal

    expect(received).toBe(expected) // Object.is equality

    Expected: ""
    Received: "Cannot load folder: folder1"

      761 |     if (thrownError) {
      762 |             console.error(thrownError);
    > 763 |             expect(thrownError.message).toBe('');
          |                                         ^
      764 |     } else {
      765 |             expect(true).toBe(true);
      766 |     }

      at toBe (testing/test-utils.ts:763:31)
          at Generator.throw (<anonymous>)
      at rejected (testing/test-utils.js:19:32)

 FAIL  ./import-enex-html-gen.test.js (45.115 s)
  ● EnexToHtml › should convert from Enex to Html: checkbox-list

    expect(received).toEqual(expected) // deep equality

    - Expected  - 15
    + Received  + 15

    - <en-note>
    + <en-note>
    -   <div>
    +   <div>
    -     <p>For example, consider an exported Evernote list with todo checkboxes like this:</p>
    +     <p>For example, consider an exported Evernote list with todo checkboxes like this:</p>
    -     <ul>
    +     <ul>
    -       <li>
    +       <li>
    -         <div><input checked="checked" type="checkbox" onclick="return false;">Foo</div>
    +         <div><input checked="checked" type="checkbox" onclick="return false;">Foo</div>
    -       </li>
    +       </li>
    -       <li>
    +       <li>
    -         <div><input type="checkbox" onclick="return false;"><b>Bar</b></div>
    +         <div><input type="checkbox" onclick="return false;"><b>Bar</b></div>
    -       </li>
    +       </li>
    -       <li>
    +       <li>
    -         <div><input type="checkbox" onclick="return false;"><i>Baz</i></div>
    +         <div><input type="checkbox" onclick="return false;"><i>Baz</i></div>
    -       </li>
    +       </li>
    -     </ul>
    +     </ul>
    -   </div>
    +   </div>
      </en-note>

      53 |              const expectedOutput = await shim.fsDriver().readFile(outputFile);
      54 |              const actualOutput = await beautifyHtml(await enexXmlToHtml(enexInput, options.resources));
    > 55 |              expect(actualOutput).toEqual(expectedOutput);
         |                                   ^
      56 |      }));
      57 | };
      58 |

      at Object.toEqual (import-enex-html-gen.test.js:55:24)

  ● EnexToHtml › should convert from Enex to Html: checklist

    expect(received).toEqual(expected) // deep equality

    - Expected  - 18
    + Received  + 18

    - <en-note>
    + <en-note>
    -   <div>
    +   <div>
    -     <p>In Evernote a checklist is not the same as a list with checkboxes.</p>
    +     <p>In Evernote a checklist is not the same as a list with checkboxes.</p>
    -     <ul style="--en-todo:true;">
    +     <ul style="--en-todo:true;">
    -       <li style="--en-checked:false;">
    +       <li style="--en-checked:false;">
    -         <input type="checkbox" onclick="return false;">
    +         <input type="checkbox" onclick="return false;">
    -         <div>One</div>
    +         <div>One</div>
    -       </li>
    +       </li>
    -       <li style="--en-checked:true;">
    +       <li style="--en-checked:true;">
    -         <input checked="checked" type="checkbox" onclick="return false;">
    +         <input checked="checked" type="checkbox" onclick="return false;">
    -         <div>Two</div>
    +         <div>Two</div>
    -       </li>
    +       </li>
    -       <li style="--en-checked:false;">
    +       <li style="--en-checked:false;">
    -         <input type="checkbox" onclick="return false;">
    +         <input type="checkbox" onclick="return false;">
    -         <div>Three</div>
    +         <div>Three</div>
    -       </li>
    +       </li>
    -     </ul>
    +     </ul>
    -   </div>
    +   </div>
      </en-note>

      53 |              const expectedOutput = await shim.fsDriver().readFile(outputFile);
      54 |              const actualOutput = await beautifyHtml(await enexXmlToHtml(enexInput, options.resources));
    > 55 |              expect(actualOutput).toEqual(expectedOutput);
         |                                   ^
      56 |      }));
      57 | };
      58 |

      at Object.toEqual (import-enex-html-gen.test.js:55:24)

  ● EnexToHtml › should convert from Enex to Html: svg

    expect(received).toEqual(expected) // deep equality

    - Expected  - 2
    + Received  + 2

    - <en-note>
    + <en-note>
    -   <div><img style="margin:0px;padding:0px;outline:0px;width:74px;height:36px;position:absolute;bottom:-5px;left:0px;transform:translate(0px, 100%);stroke-dasharray:90;transition:stroke-dashoffset 0.5s cubic-bezier(0.97, 0.16, 0.62, 0.76) 0s;stroke-dashoffset:0;" src="data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' data-evernote-id='97' class='js-evernote-checked'%3e%3cuse xlink:href='https://wordminds.com/wp-content/themes/wordminds/assets/img/hint_left.svg%23hint_left' data-evernote-id='98' class='js-evernote-checked'%3e%3c/us    %3c/svg%3e"></div>
    +   <div><img style="margin:0px;padding:0px;outline:0px;width:74px;height:36px;position:absolute;bottom:-5px;left:0px;transform:translate(0px, 100%);stroke-dasharray:90;transition:stroke-dashoffset 0.5s cubic-bezier(0.97, 0.16, 0.62, 0.76) 0s;stroke-dashoffset:0;" src="data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' data-evernote-id='97' class='js-evernote-checked'%3e%3cuse xlink:href='https://wordminds.com/wp-content/themes/wordminds/assets/img/hint_left.svg%23hint_left' data-evernote-id='98' class='js-evernote-checked'%3e%3c/use%3e%3c/svg%3e"></div>
      </en-note>

      53 |              const expectedOutput = await shim.fsDriver().readFile(outputFile);
      54 |              const actualOutput = await beautifyHtml(await enexXmlToHtml(enexInput, options.resources));
    > 55 |              expect(actualOutput).toEqual(expectedOutput);
         |                                   ^
      56 |      }));
      57 | };
      58 |

      at Object.toEqual (import-enex-html-gen.test.js:55:24)

  ● EnexToHtml › should convert from Enex to Html: en-media--image

    expect(received).toEqual(expected) // deep equality

    - Expected  - 11
    + Received  + 11

    - <en-note>
    + <en-note>
    -   <div><input type="checkbox" onclick="return false;">This is a test</div>
    +   <div><input type="checkbox" onclick="return false;">This is a test</div>
    -   <div><input type="checkbox" onclick="return false;">A test for <span style="font-weight: bold;">bold</span></div>
    +   <div><input type="checkbox" onclick="return false;">A test for <span style="font-weight: bold;">bold</span></div>
    -   <div>
    +   <div>
    -     <input type="checkbox" onclick="return false;">A test for <i>italic</i>
    +     <input type="checkbox" onclick="return false;">A test for <i>italic</i>
    -     <br>
    +     <br>
    -   </div>
    +   </div>
    -   <div>
    +   <div>
    -     <br>
    +     <br>
    -   </div>
    +   </div>
    -   <div><i><img src=":/89ce7da62c6b2832929a6964237e98e9" hash="89ce7da62c6b2832929a6964237e98e9" type="image/jpeg" alt=""></i></div> 
    +   <div><i><img src=":/89ce7da62c6b2832929a6964237e98e9" hash="89ce7da62c6b2832929a6964237e98e9" type="image/jpeg" alt=""></i></div> 
      </en-note>

      53 |              const expectedOutput = await shim.fsDriver().readFile(outputFile);
      54 |              const actualOutput = await beautifyHtml(await enexXmlToHtml(enexInput, options.resources));
    > 55 |              expect(actualOutput).toEqual(expectedOutput);
         |                                   ^
      56 |      }));
      57 | };
      58 |

      at Object.toEqual (import-enex-html-gen.test.js:55:24)

  ● EnexToHtml › should convert from Enex to Html: en-media--audio

    expect(received).toEqual(expected) // deep equality

    - Expected  - 11
    + Received  + 11

    - <en-note>
    + <en-note>
    -   <div>
    +   <div>
    -     <audio controls="" preload="none" style="width:480px;">
    +     <audio controls="" preload="none" style="width:480px;">
    -       <source src=":/9168ee833d03c5ea7c730ac6673978c1" type="audio/mp4">
    +       <source src=":/9168ee833d03c5ea7c730ac6673978c1" type="audio/mp4">
    -       <p>Your browser does not support HTML5 audio.</p>
    +       <p>Your browser does not support HTML5 audio.</p>
    -     </audio>
    +     </audio>
    -     <p><a href=":/9168ee833d03c5ea7c730ac6673978c1">audio test</a></p>
    +     <p><a href=":/9168ee833d03c5ea7c730ac6673978c1">audio test</a></p>
    -   </div>
    +   </div>
    -   <div>
    +   <div>
    -     <br>
    +     <br>
    -   </div>
    +   </div>
      </en-note>

      53 |              const expectedOutput = await shim.fsDriver().readFile(outputFile);
      54 |              const actualOutput = await beautifyHtml(await enexXmlToHtml(enexInput, options.resources));
    > 55 |              expect(actualOutput).toEqual(expectedOutput);
         |                                   ^
      56 |      }));
      57 | };
      58 |

      at Object.toEqual (import-enex-html-gen.test.js:55:24)

  ● EnexToHtml › should convert from Enex to Html: attachment

    expect(received).toEqual(expected) // deep equality

    - Expected  - 5
    + Received  + 5

    - <en-note>
    + <en-note>
    -   <div><a href=":/21ca2b948f222a38802940ec7e2e5de3" hash="21ca2b948f222a38802940ec7e2e5de3" type="application/pdf" style="cursor:poi    ;" alt="attachment-1">attachment-1</a></div>
    +   <div><a href=":/21ca2b948f222a38802940ec7e2e5de3" hash="21ca2b948f222a38802940ec7e2e5de3" type="application/pdf" style="cursor:pointer;" alt="attachment-1">attachment-1</a></div>
    -   <div>
    +   <div>
    -     <br>
    +     <br>
    -   </div>
    +   </div>
      </en-note>

      53 |              const expectedOutput = await shim.fsDriver().readFile(outputFile);
      54 |              const actualOutput = await beautifyHtml(await enexXmlToHtml(enexInput, options.resources));
    > 55 |              expect(actualOutput).toEqual(expectedOutput);
         |                                   ^
      56 |      }));
      57 | };
      58 |

      at Object.toEqual (import-enex-html-gen.test.js:55:24)

  ● EnexToHtml › should convert from Enex to Html: quoted-attributes

    expect(received).toEqual(expected) // deep equality

    - Expected  - 2
    + Received  + 2

    - <en-note>
    + <en-note>
    -   <h1 style="box-sizing:inherit;font-family:&quot;Guardian TextSans Web&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, sans-serif;margin-top:0.2em;margin-bottom:0.35em;font-size:2.125em;font-weight:600;line-height:1.3;">Association Between mRNA Vaccination and COV    9 Hospitalization and Disease Severity</h1>
    +   <h1 style="box-sizing:inherit;font-family:&quot;Guardian TextSans Web&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, sans-serif;margin-top:0.2em;margin-bottom:0.35em;font-size:2.125em;font-weight:600;line-height:1.3;">Association Between mRNA Vaccination and COVID-19 Hospitalization and Disease Severity</h1>
      </en-note>

      53 |              const expectedOutput = await shim.fsDriver().readFile(outputFile);
      54 |              const actualOutput = await beautifyHtml(await enexXmlToHtml(enexInput, options.resources));
    > 55 |              expect(actualOutput).toEqual(expectedOutput);
         |                                   ^
      56 |      }));
      57 | };
      58 |

      at Object.toEqual (import-enex-html-gen.test.js:55:24)

 FAIL  ./fsDriver.test.js
  ● fsDriver › should resolveRelativePathWithinDir

    expect(received).toBe(expected) // Object.is equality

    Expected: "c:\\test\\temp\\my\\file.txt"
    Received: "k:\\test\\temp\\my\\file.txt"

      17 |      it('should resolveRelativePathWithinDir', async () => {
      18 |              const fsDriver = new FsDriverNode();
    > 19 |              expect(fsDriver.resolveRelativePathWithinDir('/test/temp', './my/file.txt').toLowerCase()).toBe(platformPath('/test/temp/my/file.txt'));
         |                                                                                                         ^
      20 |              expect(fsDriver.resolveRelativePathWithinDir('/', './test').toLowerCase()).toBe(platformPath('/test'));
      21 |              expect(fsDriver.resolveRelativePathWithinDir('/test', 'myfile.txt').toLowerCase()).toBe(platformPath('/test/myfile.txt'));
      22 |              expect(fsDriver.resolveRelativePathWithinDir('/test/temp', './mydir/../test.txt').toLowerCase()).toBe(platformPath('/test/temp/test.txt'));

      at toBe (fsDriver.test.ts:19:94)
      at fsDriver.test.js:27:67
      at Object.<anonymous>.__awaiter (fsDriver.test.js:9:10)
      at Object.__awaiter (fsDriver.test.ts:17:55)

 FAIL  services/rest/routes/events.test.js (136.299 s)
  ● routes/events › should limit the number of response items

    thrown: "Exceeded timeout of 90000 ms for a test.
    Add a timeout value to this test to increase the timeout, if this is a long-running test. See https://jestjs.io/docs/api#testname-fn-timeout."

      57 |      });
    > 59 |      it('should limit the number of response items', async () => {
         |      ^
      60 |              const promises = [];
      61 |              for (let i = 0; i < 101; i++) {
      62 |                      promises.push(Note.save({ title: 'toto' }));

      at it (services/rest/routes/events.test.ts:59:2)
      at Object.describe (services/rest/routes/events.test.ts:10:1)


Test Suites: 8 failed, 83 passed, 91 total
Tests:       23 failed, 764 passed, 787 total
Snapshots:   0 total
Time:        1030.317 s

Tried again with Node version v18.19.1

Still getting many test fails. I've noticed that some of the test cases from different libraries interleave each other, don't know if that could be the reason. (I'm running yarn test from root)

➤ YN0000: [@joplin/lib]:       53 |             const expectedOutput = await shim.fsDriver().readFile(outputFile);
➤ YN0000: [@joplin/lib]:       54 |             const actualOutput = await beautifyHtml(await enexXmlToHtml(enexInput, options.resources));
➤ YN0000: [@joplin/lib]:     > 55 |             expect(actualOutput).toEqual(expectedOutput);
➤ YN0000: [@joplin/lib]:          |                                  ^
➤ YN0000: [@joplin/lib]:       56 |     }));
➤ YN0000: [@joplin/lib]:       57 | };
➤ YN0000: [@joplin/lib]:       58 |
➤ YN0000: [@joplin/lib]:
➤ YN0000: [@joplin/lib]:       at Object.toEqual (import-enex-html-gen.test.js:55:24)
➤ YN0000: [@joplin/lib]:
➤ YN0000: [@joplin/lib]: FAIL services/synchronizer/Synchronizer.tags.test.js (93.975 s)
➤ YN0000: [@joplin/lib]:   ● Synchronizer.tags › should sync tags
➤ YN0000: [@joplin/lib]:
➤ YN0000: [@joplin/lib]:     thrown: "Exceeded timeout of 90000 ms for a hook.
➤ YN0000: [@joplin/lib]:     Add a timeout value to this test to increase the timeout, if this is a long-running test. See https://jestjs.io/docs/api#testname-fn-timeout."
➤ YN0000: [@joplin/lib]:
➤ YN0000: [@joplin/lib]:        8 | describe('Synchronizer.tags', () => {
➤ YN0000: [@joplin/lib]:        9 |
➤ YN0000: [@joplin/lib]:     > 10 |     beforeEach(async () => {
➤ YN0000: [@joplin/lib]:          |     ^
➤ YN0000: [@joplin/lib]:       11 |             await setupDatabaseAndSynchronizer(1);
➤ YN0000: [@joplin/lib]:       12 |             await setupDatabaseAndSynchronizer(2);
➤ YN0000: [@joplin/lib]:       13 |             await switchClient(1);
➤ YN0000: [@joplin/lib]:
➤ YN0000: [@joplin/lib]:       at beforeEach (services/synchronizer/Synchronizer.tags.test.ts:10:2)
➤ YN0000: [@joplin/lib]:       at Object.describe (services/synchronizer/Synchronizer.tags.test.ts:8:1)
➤ YN0000: [@joplin/lib]:
➤ YN0000: [@joplin/lib]:   ● Synchronizer.tags › should sync encrypted tags
➤ YN0000: [@joplin/lib]:
➤ YN0000: [@joplin/lib]:     Error: SQLITE_ERROR: no such table: items_normalized: DELETE FROM items_normalized
➤ YN0000: [@joplin/lib]:
➤ YN0000: [@joplin/lib]:       21 |             if (sql) msg.push(sql);
➤ YN0000: [@joplin/lib]:       22 |             if (params) msg.push(params);
➤ YN0000: [@joplin/lib]:     > 23 |             const output = new Error(msg.join(': '));
➤ YN0000: [@joplin/lib]:          |                            ^
➤ YN0000: [@joplin/lib]:       24 |             if (error.code) output.code = error.code;
➤ YN0000: [@joplin/lib]:       25 |             return output;
➤ YN0000: [@joplin/lib]:       26 |     }
➤ YN0000: [@joplin/lib]:
➤ YN0000: [@joplin/lib]:       at DatabaseDriverNode.sqliteErrorToJsError (database-driver-node.js:23:18)
➤ YN0000: [@joplin/lib]:       at JoplinDatabase.sqliteErrorToJsError (database.ts:38:24)
➤ YN0000: [@joplin/lib]:       at JoplinDatabase.sqliteErrorToJsError (database.ts:147:17)
➤ YN0000: [@joplin/lib]:           at Generator.throw (<anonymous>)
➤ YN0000: [@joplin/lib]:       at rejected (database.js:19:32)
➤ YN0000: [@joplin/lib]:
➤ YN0000: [@joplin/lib]: FAIL ./fsDriver.test.js
➤ YN0000: [@joplin/lib]:   ● fsDriver › should resolveRelativePathWithinDir
➤ YN0000: [@joplin/lib]:
➤ YN0000: [@joplin/lib]:     expect(received).toBe(expected) // Object.is equality
➤ YN0000: [@joplin/lib]:
➤ YN0000: [@joplin/lib]:     Expected: "c:\\test\\temp\\my\\file.txt"
➤ YN0000: [@joplin/lib]:     Received: "k:\\test\\temp\\my\\file.txt"
➤ YN0000: [@joplin/lib]:
➤ YN0000: [@joplin/lib]:       17 |     it('should resolveRelativePathWithinDir', async () => {
➤ YN0000: [@joplin/lib]:       18 |             const fsDriver = new FsDriverNode();
➤ YN0000: [@joplin/lib]:     > 19 |             expect(fsDriver.resolveRelativePathWithinDir('/test/temp', './my/file.txt').toLowerCase()).toBe(platformPath('/test/temp/my/file.txt'));
➤ YN0000: [@joplin/lib]:          |                                                                                                        ^
➤ YN0000: [@joplin/lib]:       20 |             expect(fsDriver.resolveRelativePathWithinDir('/', './test').toLowerCase()).toBe(platformPath('/test'));
➤ YN0000: [@joplin/lib]:       21 |             expect(fsDriver.resolveRelativePathWithinDir('/test', 'myfile.txt').toLowerCase()).toBe(platformPath('/test/myfile.txt'));
➤ YN0000: [@joplin/lib]:       22 |             expect(fsDriver.resolveRelativePathWithinDir('/test/temp', './mydir/../test.txt').toLowerCase()).toBe(platformPath('/test/temp/test.txt'));
➤ YN0000: [@joplin/lib]:
➤ YN0000: [@joplin/lib]:       at toBe (fsDriver.test.ts:19:94)
➤ YN0000: [@joplin/lib]:       at fsDriver.test.js:27:67
➤ YN0000: [@joplin/lib]:       at Object.<anonymous>.__awaiter (fsDriver.test.js:9:10)
➤ YN0000: [@joplin/lib]:       at Object.__awaiter (fsDriver.test.ts:17:55)
➤ YN0000: [@joplin/lib]:
➤ YN0000: [@joplin/lib]: FAIL services/synchronizer/Synchronizer.ppk.test.js (110.377 s)
➤ YN0000: [@joplin/lib]:   ● Synchronizer.ppk › should not create a public private key pair if not using E2EE
➤ YN0000: [@joplin/lib]:
➤ YN0000: [@joplin/lib]:     thrown: "Exceeded timeout of 90000 ms for a hook.
➤ YN0000: [@joplin/lib]:     Add a timeout value to this test to increase the timeout, if this is a long-running test. See https://jestjs.io/docs/api#testname-fn-timeout."
➤ YN0000: [@joplin/lib]:
➤ YN0000: [@joplin/lib]:        7 | describe('Synchronizer.ppk', () => {
➤ YN0000: [@joplin/lib]:        8 |
➤ YN0000: [@joplin/lib]:     >  9 |     beforeEach(async () => {
➤ YN0000: [@joplin/lib]:          |     ^
➤ YN0000: [@joplin/lib]:       10 |             await setupDatabaseAndSynchronizer(1);
➤ YN0000: [@joplin/lib]:       11 |             await setupDatabaseAndSynchronizer(2);
➤ YN0000: [@joplin/lib]:       12 |             await switchClient(1);
➤ YN0000: [@joplin/lib]:
➤ YN0000: [@joplin/lib]:       at beforeEach (services/synchronizer/Synchronizer.ppk.test.ts:9:2)
➤ YN0000: [@joplin/lib]:       at Object.describe (services/synchronizer/Synchronizer.ppk.test.ts:7:1)
➤ YN0000: [@joplin/lib]:
➤ YN0000: [@joplin/lib]: FAIL services/synchronizer/Synchronizer.tools.test.js (107.317 s)
➤ YN0000: [@joplin/lib]:   ● Synchronizer.tools › should clear local sync data, and re-upload everything to sync target
➤ YN0000: [@joplin/lib]:
➤ YN0000: [@joplin/lib]:     thrown: "Exceeded timeout of 90000 ms for a hook.
➤ YN0000: [@joplin/lib]:     Add a timeout value to this test to increase the timeout, if this is a long-running test. See https://jestjs.io/docs/api#testname-fn-timeout."
➤ YN0000: [@joplin/lib]:
➤ YN0000: [@joplin/lib]:        7 | describe('Synchronizer.tools', () => {
➤ YN0000: [@joplin/lib]:        8 |
➤ YN0000: [@joplin/lib]:     >  9 |     beforeEach(async () => {
➤ YN0000: [@joplin/lib]:          |     ^
➤ YN0000: [@joplin/lib]:       10 |             await setupDatabaseAndSynchronizer(1);
➤ YN0000: [@joplin/lib]:       11 |             await setupDatabaseAndSynchronizer(2);
➤ YN0000: [@joplin/lib]:       12 |             await switchClient(1);
➤ YN0000: [@joplin/lib]:
➤ YN0000: [@joplin/lib]:       at beforeEach (services/synchronizer/Synchronizer.tools.test.ts:9:2)
➤ YN0000: [@joplin/lib]:       at Object.describe (services/synchronizer/Synchronizer.tools.test.ts:7:1)
➤ YN0000: [@joplin/lib]:
➤ YN0000: [@joplin/lib]: FAIL services/rest/routes/events.test.js (231.043 s)
➤ YN0000: [@joplin/lib]:   ● routes/events › should limit the number of response items
➤ YN0000: [@joplin/lib]:
➤ YN0000: [@joplin/lib]:     thrown: "Exceeded timeout of 90000 ms for a test.
➤ YN0000: [@joplin/lib]:     Add a timeout value to this test to increase the timeout, if this is a long-running test. See https://jestjs.io/docs/api#testname-fn-timeout."
➤ YN0000: [@joplin/lib]:
➤ YN0000: [@joplin/lib]:       57 |     });
➤ YN0000: [@joplin/lib]:       58 |
➤ YN0000: [@joplin/lib]:     > 59 |     it('should limit the number of response items', async () => {
➤ YN0000: [@joplin/lib]:          |     ^
➤ YN0000: [@joplin/lib]:       60 |             const promises = [];
➤ YN0000: [@joplin/lib]:       61 |             for (let i = 0; i < 101; i++) {
➤ YN0000: [@joplin/lib]:       62 |                     promises.push(Note.save({ title: 'toto' }));
➤ YN0000: [@joplin/lib]:
➤ YN0000: [@joplin/lib]:       at it (services/rest/routes/events.test.ts:59:2)
➤ YN0000: [@joplin/lib]:       at Object.describe (services/rest/routes/events.test.ts:10:1)
➤ YN0000: [@joplin/lib]:
➤ YN0000: [@joplin/lib]:
➤ YN0000: [@joplin/lib]: Test Suites: 17 failed, 74 passed, 91 total
➤ YN0000: [@joplin/lib]: Tests:       40 failed, 747 passed, 787 total
➤ YN0000: [@joplin/lib]: Snapshots:   0 total
➤ YN0000: [@joplin/lib]: Time:        1437.991 s
➤ YN0000: [@joplin/lib]: Ran all test suites.
➤ YN0000: [@joplin/lib]: Process exited (exit code 1), completed in 24m 21s
➤ YN0000: [@joplin/tools]: Process started
➤ YN0000: [@joplin/server]: PASS dist/models/ItemModel.test.js (842.187 s)
➤ YN0000: [@joplin/server]: PASS dist/routes/api/shares.resource.test.js (161.471 s)
➤ YN0000: [@joplin/server]: PASS dist/utils/routeUtils.test.js
➤ YN0000: [@joplin/tools]: PASS website/utils/applyTranslations.test.js (30.403 s)
➤ YN0000: [@joplin/tools]: PASS website/utils/frontMatter.test.js (31.1 s)
➤ YN0000: [@joplin/tools]: PASS ./update-readme-download.test.js (31.16 s)
➤ YN0000: [@joplin/tools]: PASS ./buildServerDocker.test.js
➤ YN0000: [@joplin/tools]: PASS website/utils/convertLinksToLocale.test.js
➤ YN0000: [@joplin/tools]: FAIL ./checkLibPaths.test.js
➤ YN0000: [@joplin/tools]:   ● checkLibPaths › should detect invalid lib paths
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:     expect(received).toBe(expected) // Object.is equality
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:     Expected: 1
➤ YN0000: [@joplin/tools]:     Received: 0
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       30 |                   const [expected, input] = testCase;
➤ YN0000: [@joplin/tools]:       31 |                   const actual = findInvalidImportPaths(__dirname, input.split('\n').map(l => l.trim()).join('\n'));       
➤ YN0000: [@joplin/tools]:     > 32 |                   expect(actual.length).toBe(expected);
➤ YN0000: [@joplin/tools]:          |                                         ^
➤ YN0000: [@joplin/tools]:       33 |           }
➤ YN0000: [@joplin/tools]:       34 |   });
➤ YN0000: [@joplin/tools]:       35 |
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       at toBe (checkLibPaths.test.ts:32:26)
➤ YN0000: [@joplin/tools]:       at checkLibPaths.test.js:27:67
➤ YN0000: [@joplin/tools]:       at Object.<anonymous>.__awaiter (checkLibPaths.test.js:9:10)
➤ YN0000: [@joplin/tools]:       at Object.__awaiter (checkLibPaths.test.ts:5:53)
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]: PASS ./build-release-stats.test.js (34.328 s)
➤ YN0000: [@joplin/tools]: FAIL website/processDocs.test.js (37.275 s)
➤ YN0000: [@joplin/tools]:   ● Console
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:     console.info
➤ YN0000: [@joplin/tools]:       
➤ YN0000: [@joplin/tools]:       EXPECTED =======================================
➤ YN0000: [@joplin/tools]:       This is a quote:
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       > "I never said that!"
➤ YN0000: [@joplin/tools]:       >
➤ YN0000: [@joplin/tools]:       > ― Albert Einstein
➤ YN0000: [@joplin/tools]:       ACTUAL =========================================
➤ YN0000: [@joplin/tools]:       This is a quote:
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       > "I never said that!"
➤ YN0000: [@joplin/tools]:       >
➤ YN0000: [@joplin/tools]:       > ― Albert Einstein
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       at info (website/processDocs.test.ts:40:12)
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:     console.info
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       EXPECTED =======================================
➤ YN0000: [@joplin/tools]:       This is a code block:
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       ```javascript
➤ YN0000: [@joplin/tools]:       const test = 123;
➤ YN0000: [@joplin/tools]:       console.info(test);
➤ YN0000: [@joplin/tools]:       ```
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       ## Followed by a header
➤ YN0000: [@joplin/tools]:       ACTUAL =========================================
➤ YN0000: [@joplin/tools]:       This is a code block:
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       ```javascript
➤ YN0000: [@joplin/tools]:       const test = 123;
➤ YN0000: [@joplin/tools]:       console.info(test);
➤ YN0000: [@joplin/tools]:       ```
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       ## Followed by a header
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       at info (website/processDocs.test.ts:40:12)
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:     console.info
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       EXPECTED =======================================
➤ YN0000: [@joplin/tools]:       One paragraph
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       Two paragraph
➤ YN0000: [@joplin/tools]:       ACTUAL =========================================
➤ YN0000: [@joplin/tools]:       One paragraph
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       Two paragraph
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       at info (website/processDocs.test.ts:40:12)
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:     console.info
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       EXPECTED =======================================
➤ YN0000: [@joplin/tools]:       # One
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       ## One one
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       Some text
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       ## One two
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       More text
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       # Two
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       End
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       <img src="https://example.com/img.png"/>
➤ YN0000: [@joplin/tools]:       
➤ YN0000: [@joplin/tools]:       # Image and header
➤ YN0000: [@joplin/tools]:       ACTUAL =========================================
➤ YN0000: [@joplin/tools]:       # One
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       ## One one
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       Some text
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       ## One two
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       More text
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       # Two
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       End
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       <img src="https://example.com/img.png"/>
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       # Image and header
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       at info (website/processDocs.test.ts:40:12)
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:     console.info
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       EXPECTED =======================================
➤ YN0000: [@joplin/tools]:       # Joplin Android app changelog
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       ## [android-v2.13.4](https://github.com/laurent22/joplin/releases/tag/android-v2.13.4) (Pre-release) - 2023-10-24T18:29:09Z     
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       - Fixed: Improve list toggle logic (#9103) (#9066 by Henry Heino)
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       ## [android-v2.13.2](https://github.com/laurent22/joplin/releases/tag/android-v2.13.2) (Pre-release) - 2023-10-07T16:42:16Z     
➤ YN0000: [@joplin/tools]:       ACTUAL =========================================
➤ YN0000: [@joplin/tools]:       # Joplin Android app changelog
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       ## [android-v2.13.4](https://github.com/laurent22/joplin/releases/tag/android-v2.13.4) (Pre-release) - 2023-10-24T18:29:09Z     
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       - Fixed: Improve list toggle logic (#9103) (#9066 by Henry Heino)
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       ## [android-v2.13.2](https://github.com/laurent22/joplin/releases/tag/android-v2.13.2) (Pre-release) - 2023-10-07T16:42:16Z     
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       at info (website/processDocs.test.ts:40:12)
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:     console.info
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       EXPECTED =======================================
➤ YN0000: [@joplin/tools]:       One paragraph
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       <img src="https://joplinapp.org/images/logo-text.svg" width="40"/>
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       Two paragraph
➤ YN0000: [@joplin/tools]:       ACTUAL =========================================
➤ YN0000: [@joplin/tools]:       One paragraph
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       <img src="https://joplinapp.org/images/logo-text.svg" width="40"/>
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       Two paragraph
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       at info (website/processDocs.test.ts:40:12)
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:     console.info
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       EXPECTED =======================================
➤ YN0000: [@joplin/tools]:       | Link  |
➤ YN0000: [@joplin/tools]:       | ----- |
➤ YN0000: [@joplin/tools]:       | [![Image description](https://example.com/image.svg)](https://example.com/link) |
➤ YN0000: [@joplin/tools]:       ACTUAL =========================================
➤ YN0000: [@joplin/tools]:       | Link  |
➤ YN0000: [@joplin/tools]:       | ----- |
➤ YN0000: [@joplin/tools]:       | [![Image description](https://example.com/image.svg)](https://example.com/link) |
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       at info (website/processDocs.test.ts:40:12)
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:     console.info
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       EXPECTED =======================================
➤ YN0000: [@joplin/tools]:       This needs to be converted:
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       ```
➤ YN0000: [@joplin/tools]:       Some indented
➤ YN0000: [@joplin/tools]:       Text
➤ YN0000: [@joplin/tools]:       ```
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       Unindented
➤ YN0000: [@joplin/tools]:       ACTUAL =========================================
➤ YN0000: [@joplin/tools]:       This needs to be converted:
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       ```
➤ YN0000: [@joplin/tools]:       Some indented
➤ YN0000: [@joplin/tools]:       Text
➤ YN0000: [@joplin/tools]:       ```
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       Unindented
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       at info (website/processDocs.test.ts:40:12)
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:     console.info
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       EXPECTED =======================================
➤ YN0000: [@joplin/tools]:       One image: ![some alt text](https://joplinapp.org/images/logo-text-blue.svg)
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       Some link: [hello](https://joplinapp.org)
➤ YN0000: [@joplin/tools]:       ACTUAL =========================================
➤ YN0000: [@joplin/tools]:       One image: ![some alt text](https://joplinapp.org/images/logo-text-blue.svg)
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       Some link: [hello](https://joplinapp.org)
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       at info (website/processDocs.test.ts:40:12)
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:     console.info
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       EXPECTED =======================================
➤ YN0000: [@joplin/tools]:       - One
➤ YN0000: [@joplin/tools]:       - Two
➤ YN0000: [@joplin/tools]:              - Four
➤ YN0000: [@joplin/tools]:              - Five
➤ YN0000: [@joplin/tools]:       - Six
➤ YN0000: [@joplin/tools]:              - Seven
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       Some paragraph
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       1. One
➤ YN0000: [@joplin/tools]:              1. Two
➤ YN0000: [@joplin/tools]:              2. three
➤ YN0000: [@joplin/tools]:       2. Four
➤ YN0000: [@joplin/tools]:       3. Five
➤ YN0000: [@joplin/tools]:       ACTUAL =========================================
➤ YN0000: [@joplin/tools]:       - One
➤ YN0000: [@joplin/tools]:       - Two
➤ YN0000: [@joplin/tools]:              - Four
➤ YN0000: [@joplin/tools]:              - Five
➤ YN0000: [@joplin/tools]:       - Six
➤ YN0000: [@joplin/tools]:              - Seven
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       Some paragraph
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       1. One
➤ YN0000: [@joplin/tools]:              1. Two
➤ YN0000: [@joplin/tools]:              2. three
➤ YN0000: [@joplin/tools]:       2. Four
➤ YN0000: [@joplin/tools]:       3. Five
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       at info (website/processDocs.test.ts:40:12)
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:     console.info
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       EXPECTED =======================================
➤ YN0000: [@joplin/tools]:       | First Header | Second Header |
➤ YN0000: [@joplin/tools]:       | ----- | ----- |
➤ YN0000: [@joplin/tools]:       | Content Cell A1 | Content Cell A2 |
➤ YN0000: [@joplin/tools]:       | Content Cell A2 | Content Cell B2 |
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       <img src="https://test"/>
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       | Header |
➤ YN0000: [@joplin/tools]:       | ----- |
➤ YN0000: [@joplin/tools]:       | Content |
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       Paragraph
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       # With a BR tag
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       | Header |
➤ YN0000: [@joplin/tools]:       | ----- |
➤ YN0000: [@joplin/tools]:       | Line 1<br />Line 2 |
➤ YN0000: [@joplin/tools]:       ACTUAL =========================================
➤ YN0000: [@joplin/tools]:       | First Header | Second Header |
➤ YN0000: [@joplin/tools]:       | ----- | ----- |
➤ YN0000: [@joplin/tools]:       | Content Cell A1 | Content Cell A2 |
➤ YN0000: [@joplin/tools]:       | Content Cell A2 | Content Cell B2 |
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       <img src="https://test"/>
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       | Header |
➤ YN0000: [@joplin/tools]:       | ----- |
➤ YN0000: [@joplin/tools]:       | Content |
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       Paragraph
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       # With a BR tag
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       | Header |
➤ YN0000: [@joplin/tools]:       | ----- |
➤ YN0000: [@joplin/tools]:       | Line 1<br />Line 2 |
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       at info (website/processDocs.test.ts:40:12)
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:   ● website/processDocs › process a Markdown doc: K:\CODING\gsoc-2024\joplin-fork\packages\tools\website/processDocsTestSamples/blockquotes.md
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:     expect(received).toBe(expected) // Object.is equality
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:     - Expected  - 4
➤ YN0000: [@joplin/tools]:     + Received  + 4
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:     - This is a quote:
➤ YN0000: [@joplin/tools]:     -
➤ YN0000: [@joplin/tools]:     + This is a quote:
➤ YN0000: [@joplin/tools]:     +
➤ YN0000: [@joplin/tools]:     - > "I never said that!"
➤ YN0000: [@joplin/tools]:     + > "I never said that!"
➤ YN0000: [@joplin/tools]:     - >
➤ YN0000: [@joplin/tools]:     + >
➤ YN0000: [@joplin/tools]:       > ― Albert Einstein
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       45 |           }
➤ YN0000: [@joplin/tools]:       46 |
➤ YN0000: [@joplin/tools]:     > 47 |           expect(actual).toBe(expected);
➤ YN0000: [@joplin/tools]:          |                          ^
➤ YN0000: [@joplin/tools]:       48 |   });
➤ YN0000: [@joplin/tools]:       49 |
➤ YN0000: [@joplin/tools]:       50 |   test.each([
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       at toBe (website/processDocs.test.ts:47:18)
➤ YN0000: [@joplin/tools]:       at fulfilled (website/processDocs.test.js:12:24)
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:   ● website/processDocs › process a Markdown doc: K:\CODING\gsoc-2024\joplin-fork\packages\tools\website/processDocsTestSamples/code_block.md
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:     expect(received).toBe(expected) // Object.is equality
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:     - Expected  - 7
➤ YN0000: [@joplin/tools]:     + Received  + 7
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:     - This is a code block:
➤ YN0000: [@joplin/tools]:     -
➤ YN0000: [@joplin/tools]:     + This is a code block:
➤ YN0000: [@joplin/tools]:     +
➤ YN0000: [@joplin/tools]:     - ```javascript
➤ YN0000: [@joplin/tools]:     + ```javascript
➤ YN0000: [@joplin/tools]:     - const test = 123;
➤ YN0000: [@joplin/tools]:     + const test = 123;
➤ YN0000: [@joplin/tools]:     - console.info(test);
➤ YN0000: [@joplin/tools]:     + console.info(test);
➤ YN0000: [@joplin/tools]:     - ```
➤ YN0000: [@joplin/tools]:     -
➤ YN0000: [@joplin/tools]:     + ```
➤ YN0000: [@joplin/tools]:     +
➤ YN0000: [@joplin/tools]:       ## Followed by a header
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       45 |           }
➤ YN0000: [@joplin/tools]:       46 |
➤ YN0000: [@joplin/tools]:     > 47 |           expect(actual).toBe(expected);
➤ YN0000: [@joplin/tools]:          |                          ^
➤ YN0000: [@joplin/tools]:       48 |   });
➤ YN0000: [@joplin/tools]:       49 |
➤ YN0000: [@joplin/tools]:       50 |   test.each([
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       at toBe (website/processDocs.test.ts:47:18)
➤ YN0000: [@joplin/tools]:       at fulfilled (website/processDocs.test.js:12:24)
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:   ● website/processDocs › process a Markdown doc: K:\CODING\gsoc-2024\joplin-fork\packages\tools\website/processDocsTestSamples/doc1.md
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:     expect(received).toBe(expected) // Object.is equality
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:     - Expected  - 2
➤ YN0000: [@joplin/tools]:     + Received  + 2
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:     - One paragraph
➤ YN0000: [@joplin/tools]:     -
➤ YN0000: [@joplin/tools]:     + One paragraph
➤ YN0000: [@joplin/tools]:     +
➤ YN0000: [@joplin/tools]:       Two paragraph
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       45 |           }
➤ YN0000: [@joplin/tools]:       46 |
➤ YN0000: [@joplin/tools]:     > 47 |           expect(actual).toBe(expected);
➤ YN0000: [@joplin/tools]:          |                          ^
➤ YN0000: [@joplin/tools]:       48 |   });
➤ YN0000: [@joplin/tools]:       49 |
➤ YN0000: [@joplin/tools]:       50 |   test.each([
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       at toBe (website/processDocs.test.ts:47:18)
➤ YN0000: [@joplin/tools]:       at fulfilled (website/processDocs.test.js:12:24)
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:   ● website/processDocs › process a Markdown doc: K:\CODING\gsoc-2024\joplin-fork\packages\tools\website/processDocsTestSamples/headers.md
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:     expect(received).toBe(expected) // Object.is equality
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:     - Expected  - 16
➤ YN0000: [@joplin/tools]:     + Received  + 16
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:     - # One
➤ YN0000: [@joplin/tools]:     -
➤ YN0000: [@joplin/tools]:     + # One
➤ YN0000: [@joplin/tools]:     +
➤ YN0000: [@joplin/tools]:     - ## One one
➤ YN0000: [@joplin/tools]:     -
➤ YN0000: [@joplin/tools]:     + ## One one
➤ YN0000: [@joplin/tools]:     +
➤ YN0000: [@joplin/tools]:     - Some text
➤ YN0000: [@joplin/tools]:     -
➤ YN0000: [@joplin/tools]:     + Some text
➤ YN0000: [@joplin/tools]:     +
➤ YN0000: [@joplin/tools]:     - ## One two
➤ YN0000: [@joplin/tools]:     -
➤ YN0000: [@joplin/tools]:     + ## One two
➤ YN0000: [@joplin/tools]:     +
➤ YN0000: [@joplin/tools]:     - More text
➤ YN0000: [@joplin/tools]:     -
➤ YN0000: [@joplin/tools]:     + More text
➤ YN0000: [@joplin/tools]:     +
➤ YN0000: [@joplin/tools]:     - # Two
➤ YN0000: [@joplin/tools]:     -
➤ YN0000: [@joplin/tools]:     + # Two
➤ YN0000: [@joplin/tools]:     +
➤ YN0000: [@joplin/tools]:     - End
➤ YN0000: [@joplin/tools]:     -
➤ YN0000: [@joplin/tools]:     + End
➤ YN0000: [@joplin/tools]:     +
➤ YN0000: [@joplin/tools]:     - <img src="https://example.com/img.png"/>
➤ YN0000: [@joplin/tools]:     -
➤ YN0000: [@joplin/tools]:     + <img src="https://example.com/img.png"/>
➤ YN0000: [@joplin/tools]:     +
➤ YN0000: [@joplin/tools]:       # Image and header
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       45 |           }
➤ YN0000: [@joplin/tools]:       46 |
➤ YN0000: [@joplin/tools]:     > 47 |           expect(actual).toBe(expected);
➤ YN0000: [@joplin/tools]:          |                          ^
➤ YN0000: [@joplin/tools]:       48 |   });
➤ YN0000: [@joplin/tools]:       49 |
➤ YN0000: [@joplin/tools]:       50 |   test.each([
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       at toBe (website/processDocs.test.ts:47:18)
➤ YN0000: [@joplin/tools]:       at fulfilled (website/processDocs.test.js:12:24)
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:   ● website/processDocs › process a Markdown doc: K:\CODING\gsoc-2024\joplin-fork\packages\tools\website/processDocsTestSamples/headers2.md
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:     expect(received).toBe(expected) // Object.is equality
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:     - Expected  - 6
➤ YN0000: [@joplin/tools]:     + Received  + 6
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:     - # Joplin Android app changelog
➤ YN0000: [@joplin/tools]:     -
➤ YN0000: [@joplin/tools]:     + # Joplin Android app changelog
➤ YN0000: [@joplin/tools]:     +
➤ YN0000: [@joplin/tools]:     - ## [android-v2.13.4](https://github.com/laurent22/joplin/releases/tag/android-v2.13.4) (Pre-release) - 2023-10-24T18:29:09Z     
➤ YN0000: [@joplin/tools]:     -
➤ YN0000: [@joplin/tools]:     + ## [android-v2.13.4](https://github.com/laurent22/joplin/releases/tag/android-v2.13.4) (Pre-release) - 2023-10-24T18:29:09Z     
➤ YN0000: [@joplin/tools]:     +
➤ YN0000: [@joplin/tools]:     - - Fixed: Improve list toggle logic (#9103) (#9066 by Henry Heino)
➤ YN0000: [@joplin/tools]:     -
➤ YN0000: [@joplin/tools]:     + - Fixed: Improve list toggle logic (#9103) (#9066 by Henry Heino)
➤ YN0000: [@joplin/tools]:     +
➤ YN0000: [@joplin/tools]:       ## [android-v2.13.2](https://github.com/laurent22/joplin/releases/tag/android-v2.13.2) (Pre-release) - 2023-10-07T16:42:16Z     
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       45 |           }
➤ YN0000: [@joplin/tools]:       46 |
➤ YN0000: [@joplin/tools]:     > 47 |           expect(actual).toBe(expected);
➤ YN0000: [@joplin/tools]:          |                          ^
➤ YN0000: [@joplin/tools]:       48 |   });
➤ YN0000: [@joplin/tools]:       49 |
➤ YN0000: [@joplin/tools]:       50 |   test.each([
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       at toBe (website/processDocs.test.ts:47:18)
➤ YN0000: [@joplin/tools]:       at fulfilled (website/processDocs.test.js:12:24)
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:   ● website/processDocs › process a Markdown doc: K:\CODING\gsoc-2024\joplin-fork\packages\tools\website/processDocsTestSamples/image.md
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:     expect(received).toBe(expected) // Object.is equality
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:     - Expected  - 4
➤ YN0000: [@joplin/tools]:     + Received  + 4
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:     - One paragraph
➤ YN0000: [@joplin/tools]:     -
➤ YN0000: [@joplin/tools]:     + One paragraph
➤ YN0000: [@joplin/tools]:     +
➤ YN0000: [@joplin/tools]:     - <img src="https://joplinapp.org/images/logo-text.svg" width="40"/>
➤ YN0000: [@joplin/tools]:     -
➤ YN0000: [@joplin/tools]:     + <img src="https://joplinapp.org/images/logo-text.svg" width="40"/>
➤ YN0000: [@joplin/tools]:     +
➤ YN0000: [@joplin/tools]:       Two paragraph
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       45 |           }
➤ YN0000: [@joplin/tools]:       46 |
➤ YN0000: [@joplin/tools]:     > 47 |           expect(actual).toBe(expected);
➤ YN0000: [@joplin/tools]:          |                          ^
➤ YN0000: [@joplin/tools]:       48 |   });
➤ YN0000: [@joplin/tools]:       49 |
➤ YN0000: [@joplin/tools]:       50 |   test.each([
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       at toBe (website/processDocs.test.ts:47:18)
➤ YN0000: [@joplin/tools]:       at fulfilled (website/processDocs.test.js:12:24)
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:   ● website/processDocs › process a Markdown doc: K:\CODING\gsoc-2024\joplin-fork\packages\tools\website/processDocsTestSamples/image_in_link.md
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:     expect(received).toBe(expected) // Object.is equality
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:     - Expected  - 2
➤ YN0000: [@joplin/tools]:     + Received  + 2
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:     - | Link  |
➤ YN0000: [@joplin/tools]:     + | Link  |
➤ YN0000: [@joplin/tools]:     - | ----- |
➤ YN0000: [@joplin/tools]:     + | ----- |
➤ YN0000: [@joplin/tools]:       | [![Image description](https://example.com/image.svg)](https://example.com/link) |
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       45 |           }
➤ YN0000: [@joplin/tools]:       46 |
➤ YN0000: [@joplin/tools]:     > 47 |           expect(actual).toBe(expected);
➤ YN0000: [@joplin/tools]:          |                          ^
➤ YN0000: [@joplin/tools]:       48 |   });
➤ YN0000: [@joplin/tools]:       49 |
➤ YN0000: [@joplin/tools]:       50 |   test.each([
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       at toBe (website/processDocs.test.ts:47:18)
➤ YN0000: [@joplin/tools]:       at fulfilled (website/processDocs.test.js:12:24)
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:   ● website/processDocs › process a Markdown doc: K:\CODING\gsoc-2024\joplin-fork\packages\tools\website/processDocsTestSamples/indented_block.md
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:     expect(received).toBe(expected) // Object.is equality
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:     - Expected  - 7
➤ YN0000: [@joplin/tools]:     + Received  + 7
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:     - This needs to be converted:
➤ YN0000: [@joplin/tools]:     -
➤ YN0000: [@joplin/tools]:     + This needs to be converted:
➤ YN0000: [@joplin/tools]:     +
➤ YN0000: [@joplin/tools]:     - ```
➤ YN0000: [@joplin/tools]:     + ```
➤ YN0000: [@joplin/tools]:     - Some indented
➤ YN0000: [@joplin/tools]:     + Some indented
➤ YN0000: [@joplin/tools]:     - Text
➤ YN0000: [@joplin/tools]:     + Text
➤ YN0000: [@joplin/tools]:     - ```
➤ YN0000: [@joplin/tools]:     -
➤ YN0000: [@joplin/tools]:     + ```
➤ YN0000: [@joplin/tools]:     +
➤ YN0000: [@joplin/tools]:       Unindented
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       45 |           }
➤ YN0000: [@joplin/tools]:       46 |
➤ YN0000: [@joplin/tools]:     > 47 |           expect(actual).toBe(expected);
➤ YN0000: [@joplin/tools]:          |                          ^
➤ YN0000: [@joplin/tools]:       48 |   });
➤ YN0000: [@joplin/tools]:       49 |
➤ YN0000: [@joplin/tools]:       50 |   test.each([
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       at toBe (website/processDocs.test.ts:47:18)
➤ YN0000: [@joplin/tools]:       at fulfilled (website/processDocs.test.js:12:24)
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:   ● website/processDocs › process a Markdown doc: K:\CODING\gsoc-2024\joplin-fork\packages\tools\website/processDocsTestSamples/links.md
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:     expect(received).toBe(expected) // Object.is equality
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:     - Expected  - 2
➤ YN0000: [@joplin/tools]:     + Received  + 2
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:     - One image: ![some alt text](https://joplinapp.org/images/logo-text-blue.svg)
➤ YN0000: [@joplin/tools]:     -
➤ YN0000: [@joplin/tools]:     + One image: ![some alt text](https://joplinapp.org/images/logo-text-blue.svg)
➤ YN0000: [@joplin/tools]:     +
➤ YN0000: [@joplin/tools]:       Some link: [hello](https://joplinapp.org)
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       45 |           }
➤ YN0000: [@joplin/tools]:       46 |
➤ YN0000: [@joplin/tools]:     > 47 |           expect(actual).toBe(expected);
➤ YN0000: [@joplin/tools]:          |                          ^
➤ YN0000: [@joplin/tools]:       48 |   });
➤ YN0000: [@joplin/tools]:       49 |
➤ YN0000: [@joplin/tools]:       50 |   test.each([
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       at toBe (website/processDocs.test.ts:47:18)
➤ YN0000: [@joplin/tools]:       at fulfilled (website/processDocs.test.js:12:24)
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:   ● website/processDocs › process a Markdown doc: K:\CODING\gsoc-2024\joplin-fork\packages\tools\website/processDocsTestSamples/list.md
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:     expect(received).toBe(expected) // Object.is equality
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:     - Expected  - 13
➤ YN0000: [@joplin/tools]:     + Received  + 13
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:     - - One
➤ YN0000: [@joplin/tools]:     + - One
➤ YN0000: [@joplin/tools]:     - - Two
➤ YN0000: [@joplin/tools]:     + - Two
➤ YN0000: [@joplin/tools]:     -        - Four
➤ YN0000: [@joplin/tools]:     +        - Four
➤ YN0000: [@joplin/tools]:     -        - Five
➤ YN0000: [@joplin/tools]:     +        - Five
➤ YN0000: [@joplin/tools]:     - - Six
➤ YN0000: [@joplin/tools]:     + - Six
➤ YN0000: [@joplin/tools]:     -        - Seven
➤ YN0000: [@joplin/tools]:     -
➤ YN0000: [@joplin/tools]:     +        - Seven
➤ YN0000: [@joplin/tools]:     +
➤ YN0000: [@joplin/tools]:     - Some paragraph
➤ YN0000: [@joplin/tools]:     -
➤ YN0000: [@joplin/tools]:     + Some paragraph
➤ YN0000: [@joplin/tools]:     +
➤ YN0000: [@joplin/tools]:     - 1. One
➤ YN0000: [@joplin/tools]:     + 1. One
➤ YN0000: [@joplin/tools]:     -        1. Two
➤ YN0000: [@joplin/tools]:     +        1. Two
➤ YN0000: [@joplin/tools]:     -        2. three
➤ YN0000: [@joplin/tools]:     +        2. three
➤ YN0000: [@joplin/tools]:     - 2. Four
➤ YN0000: [@joplin/tools]:     + 2. Four
➤ YN0000: [@joplin/tools]:       3. Five
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       45 |           }
➤ YN0000: [@joplin/tools]:       46 |
➤ YN0000: [@joplin/tools]:     > 47 |           expect(actual).toBe(expected);
➤ YN0000: [@joplin/tools]:          |                          ^
➤ YN0000: [@joplin/tools]:       48 |   });
➤ YN0000: [@joplin/tools]:       49 |
➤ YN0000: [@joplin/tools]:       50 |   test.each([
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       at toBe (website/processDocs.test.ts:47:18)
➤ YN0000: [@joplin/tools]:       at fulfilled (website/processDocs.test.js:12:24)
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:   ● website/processDocs › process a Markdown doc: K:\CODING\gsoc-2024\joplin-fork\packages\tools\website/processDocsTestSamples/table.md
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:     expect(received).toBe(expected) // Object.is equality
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:     - Expected  - 17
➤ YN0000: [@joplin/tools]:     + Received  + 17
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:     - | First Header | Second Header |
➤ YN0000: [@joplin/tools]:     + | First Header | Second Header |
➤ YN0000: [@joplin/tools]:     - | ----- | ----- |
➤ YN0000: [@joplin/tools]:     + | ----- | ----- |
➤ YN0000: [@joplin/tools]:     - | Content Cell A1 | Content Cell A2 |
➤ YN0000: [@joplin/tools]:     + | Content Cell A1 | Content Cell A2 |
➤ YN0000: [@joplin/tools]:     - | Content Cell A2 | Content Cell B2 |
➤ YN0000: [@joplin/tools]:     -
➤ YN0000: [@joplin/tools]:     + | Content Cell A2 | Content Cell B2 |
➤ YN0000: [@joplin/tools]:     +
➤ YN0000: [@joplin/tools]:     - <img src="https://test"/>
➤ YN0000: [@joplin/tools]:     -
➤ YN0000: [@joplin/tools]:     + <img src="https://test"/>
➤ YN0000: [@joplin/tools]:     +
➤ YN0000: [@joplin/tools]:     - | Header |
➤ YN0000: [@joplin/tools]:     + | Header |
➤ YN0000: [@joplin/tools]:     - | ----- |
➤ YN0000: [@joplin/tools]:     + | ----- |
➤ YN0000: [@joplin/tools]:     - | Content |
➤ YN0000: [@joplin/tools]:     -
➤ YN0000: [@joplin/tools]:     + | Content |
➤ YN0000: [@joplin/tools]:     +
➤ YN0000: [@joplin/tools]:     - Paragraph
➤ YN0000: [@joplin/tools]:     -
➤ YN0000: [@joplin/tools]:     + Paragraph
➤ YN0000: [@joplin/tools]:     +
➤ YN0000: [@joplin/tools]:     - # With a BR tag
➤ YN0000: [@joplin/tools]:     -
➤ YN0000: [@joplin/tools]:     + # With a BR tag
➤ YN0000: [@joplin/tools]:     +
➤ YN0000: [@joplin/tools]:     - | Header |
➤ YN0000: [@joplin/tools]:     + | Header |
➤ YN0000: [@joplin/tools]:     - | ----- |
➤ YN0000: [@joplin/tools]:     + | ----- |
➤ YN0000: [@joplin/tools]:       | Line 1<br />Line 2 |
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       45 |           }
➤ YN0000: [@joplin/tools]:       46 |
➤ YN0000: [@joplin/tools]:     > 47 |           expect(actual).toBe(expected);
➤ YN0000: [@joplin/tools]:          |                          ^
➤ YN0000: [@joplin/tools]:       48 |   });
➤ YN0000: [@joplin/tools]:       49 |
➤ YN0000: [@joplin/tools]:       50 |   test.each([
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]:       at toBe (website/processDocs.test.ts:47:18)
➤ YN0000: [@joplin/tools]:       at fulfilled (website/processDocs.test.js:12:24)
➤ YN0000: [@joplin/tools]:
➤ YN0000: [@joplin/tools]: PASS website/utils/openGraph.test.js (55.042 s)
➤ YN0000: [@joplin/tools]: PASS ./git-changelog.test.js (55.285 s)
➤ YN0000: [@joplin/tools]: 
➤ YN0000: [@joplin/tools]: Test Suites: 2 failed, 8 passed, 10 total
➤ YN0000: [@joplin/tools]: Tests:       12 failed, 21 passed, 33 total
➤ YN0000: [@joplin/tools]: Snapshots:   0 total
➤ YN0000: [@joplin/tools]: Time:        60.15 s
➤ YN0000: [@joplin/tools]: Ran all test suites.
➤ YN0000: [@joplin/tools]: Process exited (exit code 1), completed in 2m 12s
➤ YN0000: [@joplin/utils]: Process started
➤ YN0000: [@joplin/server]: PASS dist/routes/api/items.test.js (995.105 s)
➤ YN0000: [@joplin/server]: PASS dist/models/UserDeletionModel.test.js (136.859 s)
➤ YN0000: [@joplin/utils]: PASS ./url.test.ts
➤ YN0000: [@joplin/utils]: PASS ./commandToString.test.ts
➤ YN0000: [@joplin/utils]: PASS ./path.test.ts
➤ YN0000: [@joplin/utils]: PASS ./html.test.ts
➤ YN0000: [@joplin/utils]: PASS ./markdown.test.ts
➤ YN0000: [@joplin/utils]: 
➤ YN0000: [@joplin/utils]: Test Suites: 5 passed, 5 total
➤ YN0000: [@joplin/utils]: Tests:       28 passed, 28 total
➤ YN0000: [@joplin/utils]: Snapshots:   0 total
➤ YN0000: [@joplin/utils]: Time:        52.127 s
➤ YN0000: [@joplin/utils]: Ran all test suites.
➤ YN0000: [@joplin/utils]: Process exited (exit code 0), completed in 1m 52s
➤ YN0000: [@joplin/server]: PASS dist/services/UserDeletionService.test.js (273.383 s)
➤ YN0000: [@joplin/server]: PASS dist/routes/admin/users.test.js (286.638 s)
➤ YN0000: [@joplin/server]: PASS dist/models/ShareModel.test.js (354.947 s)
➤ YN0000: [@joplin/server]: PASS dist/routes/index/shares.link.test.js (426.839 s)
➤ YN0000: [@joplin/server]: PASS dist/models/LockModel.test.js (117.518 s)
➤ YN0000: [@joplin/server]: PASS dist/models/utils/pagination.test.js
➤ YN0000: [@joplin/server]: PASS dist/routes/api/sessions.test.js (207.74 s)
➤ YN0000: [@joplin/server]: PASS dist/middleware/notificationHandler.test.js (137.822 s)
➤ YN0000: [@joplin/server]: PASS dist/models/ItemResourceModel.test.js (95.492 s)
➤ YN0000: [@joplin/server]: PASS dist/services/TaskService.test.js (107.366 s)
➤ YN0000: [@joplin/server]: PASS dist/routes/api/share_users.test.js (147.447 s)
➤ YN0000: [@joplin/server]: PASS dist/routes/index/login.test.js (148.287 s)
➤ YN0000: [@joplin/server]: PASS dist/routes/index/password.test.js (113.54 s)
➤ YN0000: [@joplin/server]: PASS dist/routes/api/shares.test.js (77.702 s)
➤ YN0000: [@joplin/server]: PASS dist/migrations/tests/20220131185922_account_disabled_timestamp.test.js
➤ YN0000: [@joplin/server]: PASS dist/middleware/checkAdminHandler.test.js (126.495 s)
➤ YN0000: [@joplin/server]: PASS dist/models/UserFlagModel.test.js (92.398 s)
➤ YN0000: [@joplin/server]: PASS dist/models/NotificationModel.test.js (122.572 s)
➤ YN0000: [@joplin/server]: PASS dist/routes/api/users.test.js (183.472 s)
➤ YN0000: [@joplin/server]: PASS dist/routes/admin/utils/users/impersonate.test.js (96.27 s)
➤ YN0000: [@joplin/server]: FAIL dist/db.test.js (132.138 s)
➤ YN0000: [@joplin/server]:   ● db › should allow upgrading and downgrading schema
➤ YN0000: [@joplin/server]:
➤ YN0000: [@joplin/server]:     thrown: "Exceeded timeout of 60000 ms for a test.
➤ YN0000: [@joplin/server]:     Add a timeout value to this test to increase the timeout, if this is a long-running test. See https://jestjs.io/docs/api#testname-fn-timeout."
➤ YN0000: [@joplin/server]:
➤ YN0000: [@joplin/server]:       18 |  });
➤ YN0000: [@joplin/server]:       19 |
➤ YN0000: [@joplin/server]:     > 20 |  it('should allow upgrading and downgrading schema', async () => {
➤ YN0000: [@joplin/server]:          |  ^
➤ YN0000: [@joplin/server]:       21 |          // Migrations before that didn't have a down() step.
➤ YN0000: [@joplin/server]:       22 |          const ignoreAllBefore = '20210819165350_user_flags';
➤ YN0000: [@joplin/server]:       23 |
➤ YN0000: [@joplin/server]:
➤ YN0000: [@joplin/server]:       at it (src/db.test.ts:20:2)
➤ YN0000: [@joplin/server]:       at Object.describe (src/db.test.ts:9:1)
➤ YN0000: [@joplin/server]:
➤ YN0000: [@joplin/server]:   ● db › should tell if a migration is required
➤ YN0000: [@joplin/server]:
➤ YN0000: [@joplin/server]:     EBUSY: resource busy or locked, unlink 'K:\CODING\gsoc-2024\joplin-fork\packages\server\temp\test-db\joplin.sqlite'
➤ YN0000: [@joplin/server]:
➤ YN0000: [@joplin/server]:
➤ YN0000: [@joplin/server]:
➤ YN0000: [@joplin/server]: PASS dist/models/items/storage/StorageDriverS3.test.js
➤ YN0000: [@joplin/server]: PASS dist/routes/index/signup.test.js (63.08 s)
➤ YN0000: [@joplin/server]: PASS dist/models/SubscriptionModel.test.js (75.611 s)
➤ YN0000: [@joplin/server]: PASS dist/middleware/apiVersionHandler.test.js (105.542 s)
➤ YN0000: [@joplin/server]: PASS dist/models/items/storage/parseStorageConnectionString.test.js
➤ YN0000: [@joplin/server]: FAIL dist/routes/index/items.test.js (118.221 s)
➤ YN0000: [@joplin/server]:   ● index_items › should list the user items
➤ YN0000: [@joplin/server]:
➤ YN0000: [@joplin/server]:     thrown: "Exceeded timeout of 60000 ms for a test.
➤ YN0000: [@joplin/server]:     Add a timeout value to this test to increase the timeout, if this is a long-running test. See https://jestjs.io/docs/api#testname-fn-timeout."
➤ YN0000: [@joplin/server]:
➤ YN0000: [@joplin/server]:       16 |  });
➤ YN0000: [@joplin/server]:       17 |
➤ YN0000: [@joplin/server]:     > 18 |  test('should list the user items', async () => {
➤ YN0000: [@joplin/server]:          |  ^
➤ YN0000: [@joplin/server]:       19 |          const { user: user1, session: session1 } = await createUserAndSession(1, true);
➤ YN0000: [@joplin/server]:       20 |
➤ YN0000: [@joplin/server]:       21 |          const items: any = {};
➤ YN0000: [@joplin/server]:
➤ YN0000: [@joplin/server]:       at test (src/routes/index/items.test.ts:18:2)
➤ YN0000: [@joplin/server]:       at Object.describe (src/routes/index/items.test.ts:4:1)
➤ YN0000: [@joplin/server]:
➤ YN0000: [@joplin/server]: PASS dist/models/items/storage/loadStorageDriver.test.js (70.349 s)
➤ YN0000: [@joplin/server]: PASS dist/models/items/storage/StorageDriverFs.test.js (262.445 s)
➤ YN0000: [@joplin/server]: PASS dist/env.test.js (82.514 s)
➤ YN0000: [@joplin/server]: PASS dist/models/EventModel.test.js (68.738 s)
➤ YN0000: [@joplin/server]: PASS dist/routes/index/notifications.test.js (65.157 s)
➤ YN0000: [@joplin/server]: PASS dist/models/SessionModel.test.js
➤ YN0000: [@joplin/server]: PASS dist/routes/index/changes.test.js
➤ YN0000: [@joplin/server]: PASS dist/services/email/utils.test.js
➤ YN0000: [@joplin/server]: PASS dist/models/EmailModel.test.js
➤ YN0000: [@joplin/server]: PASS dist/models/items/storage/StorageDriverDatabase.test.js (236.734 s)
➤ YN0000: [@joplin/server]: FAIL dist/routes/api/shares.folder.test.js (1671.499 s)
➤ YN0000: [@joplin/server]:   ● shares.folder › should update share status when note parent changes
➤ YN0000: [@joplin/server]:
➤ YN0000: [@joplin/server]:     thrown: "Exceeded timeout of 60000 ms for a test.
➤ YN0000: [@joplin/server]:     Add a timeout value to this test to increase the timeout, if this is a long-running test. See https://jestjs.io/docs/api#testname-fn-timeout."
➤ YN0000: [@joplin/server]:
➤ YN0000: [@joplin/server]:       214 |         });
➤ YN0000: [@joplin/server]:       215 |
➤ YN0000: [@joplin/server]:     > 216 |         test('should update share status when note parent changes', async () => {
➤ YN0000: [@joplin/server]:           |         ^
➤ YN0000: [@joplin/server]:       217 |                 const { user: user1, session: session1 } = await createUserAndSession(1);
➤ YN0000: [@joplin/server]:       218 |                 const { user: user2, session: session2 } = await createUserAndSession(2);
➤ YN0000: [@joplin/server]:       219 |
➤ YN0000: [@joplin/server]:
➤ YN0000: [@joplin/server]:       at test (src/routes/api/shares.folder.test.ts:216:2)
➤ YN0000: [@joplin/server]:       at Object.describe (src/routes/api/shares.folder.test.ts:12:1)
➤ YN0000: [@joplin/server]:
➤ YN0000: [@joplin/server]: PASS dist/middleware/ownerHandler.test.js (85.695 s)
➤ YN0000: [@joplin/server]: PASS dist/utils/joplinUtils.test.js
➤ YN0000: [@joplin/server]: PASS dist/utils/auth.test.js
➤ YN0000: [@joplin/server]: PASS dist/utils/bytes.test.js
➤ YN0000: [@joplin/server]: PASS dist/utils/time.test.js
➤ YN0000: [@joplin/server]: PASS dist/models/utils/user.test.js
➤ YN0000: [@joplin/server]: PASS dist/routes/index/logout.test.js (62.815 s)
➤ YN0000: [@joplin/server]: PASS dist/models/TokenModel.test.js
➤ YN0000: [@joplin/server]: PASS dist/models/KeyValueModel.test.js (68.509 s)
➤ YN0000: [@joplin/server]: PASS dist/routes/index/home.test.js
➤ YN0000: [@joplin/server]: PASS dist/routes/api/ping.test.js
➤ YN0000: [@joplin/server]: PASS dist/models/items/storage/StorageDriverMemory.test.js (191.205 s)
➤ YN0000: [@joplin/server]: 
➤ YN0000: [@joplin/server]: Summary of all failing tests
➤ YN0000: [@joplin/server]: FAIL dist/db.test.js (132.138 s)
➤ YN0000: [@joplin/server]:   ● db › should allow upgrading and downgrading schema
➤ YN0000: [@joplin/server]:
➤ YN0000: [@joplin/server]:     thrown: "Exceeded timeout of 60000 ms for a test.
➤ YN0000: [@joplin/server]:     Add a timeout value to this test to increase the timeout, if this is a long-running test. See https://jestjs.io/docs/api#testname-fn-timeout."
➤ YN0000: [@joplin/server]:
➤ YN0000: [@joplin/server]:       18 |  });
➤ YN0000: [@joplin/server]:       19 |
➤ YN0000: [@joplin/server]:     > 20 |  it('should allow upgrading and downgrading schema', async () => {
➤ YN0000: [@joplin/server]:          |  ^
➤ YN0000: [@joplin/server]:       21 |          // Migrations before that didn't have a down() step.
➤ YN0000: [@joplin/server]:       22 |          const ignoreAllBefore = '20210819165350_user_flags';
➤ YN0000: [@joplin/server]:       23 |
➤ YN0000: [@joplin/server]:
➤ YN0000: [@joplin/server]:       at it (src/db.test.ts:20:2)
➤ YN0000: [@joplin/server]:       at Object.describe (src/db.test.ts:9:1)
➤ YN0000: [@joplin/server]:
➤ YN0000: [@joplin/server]:   ● db › should tell if a migration is required
➤ YN0000: [@joplin/server]:
➤ YN0000: [@joplin/server]:     EBUSY: resource busy or locked, unlink 'K:\CODING\gsoc-2024\joplin-fork\packages\server\temp\test-db\joplin.sqlite'
➤ YN0000: [@joplin/server]:
➤ YN0000: [@joplin/server]:
➤ YN0000: [@joplin/server]:
➤ YN0000: [@joplin/server]: FAIL dist/routes/index/items.test.js (118.221 s)
➤ YN0000: [@joplin/server]:   ● index_items › should list the user items
➤ YN0000: [@joplin/server]:
➤ YN0000: [@joplin/server]:     thrown: "Exceeded timeout of 60000 ms for a test.
➤ YN0000: [@joplin/server]:     Add a timeout value to this test to increase the timeout, if this is a long-running test. See https://jestjs.io/docs/api#testname-fn-timeout."
➤ YN0000: [@joplin/server]:
➤ YN0000: [@joplin/server]:       16 |  });
➤ YN0000: [@joplin/server]:       17 |
➤ YN0000: [@joplin/server]:     > 18 |  test('should list the user items', async () => {
➤ YN0000: [@joplin/server]:          |  ^
➤ YN0000: [@joplin/server]:       19 |          const { user: user1, session: session1 } = await createUserAndSession(1, true);
➤ YN0000: [@joplin/server]:       20 |
➤ YN0000: [@joplin/server]:       21 |          const items: any = {};
➤ YN0000: [@joplin/server]:
➤ YN0000: [@joplin/server]:       at test (src/routes/index/items.test.ts:18:2)
➤ YN0000: [@joplin/server]:       at Object.describe (src/routes/index/items.test.ts:4:1)
➤ YN0000: [@joplin/server]:
➤ YN0000: [@joplin/server]: FAIL dist/routes/api/shares.folder.test.js (1671.499 s)
➤ YN0000: [@joplin/server]:   ● shares.folder › should update share status when note parent changes
➤ YN0000: [@joplin/server]:
➤ YN0000: [@joplin/server]:     thrown: "Exceeded timeout of 60000 ms for a test.
➤ YN0000: [@joplin/server]:     Add a timeout value to this test to increase the timeout, if this is a long-running test. See https://jestjs.io/docs/api#testname-fn-timeout."
➤ YN0000: [@joplin/server]:
➤ YN0000: [@joplin/server]:       214 |         });
➤ YN0000: [@joplin/server]:       215 |
➤ YN0000: [@joplin/server]:     > 216 |         test('should update share status when note parent changes', async () => {
➤ YN0000: [@joplin/server]:           |         ^
➤ YN0000: [@joplin/server]:       217 |                 const { user: user1, session: session1 } = await createUserAndSession(1);
➤ YN0000: [@joplin/server]:       218 |                 const { user: user2, session: session2 } = await createUserAndSession(2);
➤ YN0000: [@joplin/server]:       219 |
➤ YN0000: [@joplin/server]:
➤ YN0000: [@joplin/server]:       at test (src/routes/api/shares.folder.test.ts:216:2)
➤ YN0000: [@joplin/server]:       at Object.describe (src/routes/api/shares.folder.test.ts:12:1)
➤ YN0000: [@joplin/server]:
➤ YN0000: [@joplin/server]:
➤ YN0000: [@joplin/server]: Test Suites: 3 failed, 56 passed, 59 total
➤ YN0000: [@joplin/server]: Tests:       4 failed, 263 passed, 267 total
➤ YN0000: [@joplin/server]: Snapshots:   0 total
➤ YN0000: [@joplin/server]: Time:        1731.406 s
➤ YN0000: [@joplin/server]: Ran all test suites.
➤ YN0000: [@joplin/server]: Process exited (exit code 1), completed in 30m 4s

No one has any ideas? Was really looking forward to contributing.

Or maybe I can just depend on the CI's testing for PRs but will be an annoyance for debugging.

This one is a bug in the test itself. Could you fix it?

It seems there's also something wrong with the newlines. Make sure git is not doing anything stupid with them (never understood why it would mess with this). In particular core.autocrlf must be false and maybe safecrlf too. Google it to find out how to set this globally.

Set core.autocrlf and safecrlf to false and re-cloned the project.
Failed tests from testing package/lib decreased to 5:

 PASS  services/e2ee/utils.test.js (68.639 s)   
A worker process has failed to exit gracefully and has been force exited. This is likely caused by tests leaking due to improper teardown. Try running with --detectOpenHandles to find leaks. Active timers can also cause this, ensure that .unref() was called on them.

Summary of all failing tests
 FAIL  services/RevisionService.test.js (224.632 s)
  ● services/RevisionService › should not create a revision if there is already a recent one

    expect(received).toBe(expected) // Object.is equality

    Expected: true
    Received: false

      470 |             await Note.save({ id: n1_v0.id, title: 'hello 3' });
      471 |             await revisionService().collectRevisions(); // No rev because time since last rev is less than the required 'interval between 
revisions'
    > 472 |             expect(Date.now() - interval < timeRev2).toBe(true); // check the computer is not too slow for this test
          |                                                      ^
      473 |             expect((await Revision.all()).length).toBe(2);
      474 |     }));
      475 |

      at toBe (services/RevisionService.test.ts:472:44)
      at fulfilled (services/RevisionService.test.js:12:24)

 FAIL  models/Folder.test.js (284.1 s)
  ● models/Folder › should recursively delete notes and sub-folders

    thrown: "Exceeded timeout of 90000 ms for a test.
    Add a timeout value to this test to increase the timeout, if this is a long-running test. See https://jestjs.io/docs/api#testname-fn-timeout."    

      34 |      }));
      35 |
    > 36 |      it('should recursively delete notes and sub-folders', (async () => {
         |      ^
      37 |              const f1 = await Folder.save({ title: 'folder1' });
      38 |              const f2 = await Folder.save({ title: 'folder2', parent_id: f1.id });
      39 |              const f3 = await Folder.save({ title: 'folder3', parent_id: f2.id });

      at it (models/Folder.test.ts:36:2)
      at Object.describe (models/Folder.test.ts:13:1)

 FAIL  services/rest/routes/events.test.js (287.133 s)
  ● routes/events › should limit the number of response items

    thrown: "Exceeded timeout of 90000 ms for a test.
    Add a timeout value to this test to increase the timeout, if this is a long-running test. See https://jestjs.io/docs/api#testname-fn-timeout."    

      57 |      });
      58 |
    > 59 |      it('should limit the number of response items', async () => {
         |      ^
      60 |              const promises = [];
      61 |              for (let i = 0; i < 101; i++) {
      62 |                      promises.push(Note.save({ title: 'toto' }));

      at it (services/rest/routes/events.test.ts:59:2)
      at Object.describe (services/rest/routes/events.test.ts:10:1)

 FAIL  ./fsDriver.test.js
  ● fsDriver › should resolveRelativePathWithinDir

    expect(received).toBe(expected) // Object.is equality

    Expected: "c:\\test\\temp\\my\\file.txt"
    Received: "k:\\test\\temp\\my\\file.txt"

      17 |      it('should resolveRelativePathWithinDir', async () => {
      18 |              const fsDriver = new FsDriverNode();
    > 19 |              expect(fsDriver.resolveRelativePathWithinDir('/test/temp', './my/file.txt').toLowerCase()).toBe(platformPath('/test/temp/my/file.txt'));
         |                                                                                                         ^
      20 |              expect(fsDriver.resolveRelativePathWithinDir('/', './test').toLowerCase()).toBe(platformPath('/test'));
      21 |              expect(fsDriver.resolveRelativePathWithinDir('/test', 'myfile.txt').toLowerCase()).toBe(platformPath('/test/myfile.txt'));    
      22 |              expect(fsDriver.resolveRelativePathWithinDir('/test/temp', './mydir/../test.txt').toLowerCase()).toBe(platformPath('/test/temp/test.txt'));

      at toBe (fsDriver.test.ts:19:94)
      at fsDriver.test.js:27:67
      at Object.<anonymous>.__awaiter (fsDriver.test.js:9:10)
      at Object.__awaiter (fsDriver.test.ts:17:55)

 FAIL  services/rest/Api.test.js (395.034 s)
  ● services_rest_Api › should create notes with pdf embeds

    expect(received).toBe(expected) // Object.is equality

    Expected: true
    Received: false

      518 |
      519 |             const resource = resources[0];
    > 520 |             expect(response.body.indexOf(resource.id) >= 0).toBe(true);
          |                                                             ^
      521 |     }));
      522 |
      523 |     it('should handle tokens', (async () => {

      at toBe (services/rest/Api.test.ts:520:51)
      at fulfilled (services/rest/Api.test.js:12:24)


Test Suites: 5 failed, 86 passed, 91 total
Tests:       5 failed, 782 passed, 787 total
Snapshots:   0 total
Time:        1255.167 s, estimated 1388 s
Ran all test suites.

Are all these remaining ones related to the mentioned bug?

I don't think any of these test failures are related to your changes. 3 of them seem to be because your computer is not fast enough, 1 is the issue I mentioned above (a good opportunity for a PR if you want to fix this), and this one I'm not sure:

FAIL services/rest/Api.test.js (395.034 s)
● services_rest_Api › should create notes with pdf embeds

I'd say ignore it for now and let's see how it goes on CI once you create your PR.

1 Like

Sure. Opened a PR to fix the fsDriver test: All: Fix `packages\lib\fsDriver.test.ts` test file on Windows by Deadreyo · Pull Request #10053 · laurent22/joplin · GitHub