From 8364546e70f15e3581ab47cc5f20de7f43b6350f Mon Sep 17 00:00:00 2001 From: John McLear Date: Fri, 19 Feb 2021 13:24:54 +0000 Subject: [PATCH] tests: fix importexport tests The testing approach was redone to fix numerous issues: * Even if the tests had been working, none of them would have caught https://github.com/ether/etherpad-lite/issues/4808 because they didn't exercise the client-side import logic. Now they do. * Follow-up logic was not in the `helper.waitFor()` callback like it should have been. Now the code uses `async` and `await` to ensure proper execution order. * All `$.ajax()` calls used `async: false`. Now they're properly asynchronous. * The `helper.waitFor()` condition callbacks threw instead of returning false. * The string comparisons didn't allow for different attribute order (e.g., `
    ` vs. `
      `). Now `Node.isEqualNode()` is used to reduce fragility. (`Node.isEqualNode()` is not perfect, so the tests are still a bit fragile: If class names or style strings are in a different order then `Node.isEqualNode()` will return false even if the nodes are semantically equivalent.) Co-authored-by: Richard Hansen --- src/tests/frontend/specs/importexport.js | 917 +++++++++++++++-------- 1 file changed, 596 insertions(+), 321 deletions(-) diff --git a/src/tests/frontend/specs/importexport.js b/src/tests/frontend/specs/importexport.js index 4eb95eeb..73798eca 100644 --- a/src/tests/frontend/specs/importexport.js +++ b/src/tests/frontend/specs/importexport.js @@ -1,329 +1,604 @@ 'use strict'; -describe('import functionality', function () { - beforeEach(function (cb) { - helper.newPad(cb); // creates a new pad - this.timeout(60000); - }); - - function getinnertext() { - const inner = helper.padInner$; - if (!inner) { - return ''; - } - let newtext = ''; - inner('div').each((line, el) => { - newtext += `${el.innerHTML}\n`; - }); - return newtext; - } - function importrequest(data, importurl, type) { - let error; - const result = $.ajax({ - url: importurl, - type: 'post', - processData: false, - async: false, - contentType: 'multipart/form-data; boundary=boundary', - accepts: { - text: 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', - }, - data: [ - 'Content-Type: multipart/form-data; boundary=--boundary', - '', - '--boundary', - `Content-Disposition: form-data; name="file"; filename="import.${type}"`, - 'Content-Type: text/plain', - '', - data, - '', - '--boundary', - ].join('\r\n'), - error(res) { - error = res; - }, - }); - expect(error).to.be(undefined); - return result; - } - function exportfunc(link) { - const exportresults = []; - $.ajaxSetup({ - async: false, - }); - $.get(`${link}/export/html`, (data) => { - const start = data.indexOf(''); - const end = data.indexOf(''); - const html = data.substr(start + 6, end - start - 6); - exportresults.push(['html', html]); - }); - $.get(`${link}/export/txt`, (data) => { - exportresults.push(['txt', data]); - }); - return exportresults; - } - - xit('import a pad with newlines from txt', function (done) { - const importurl = `${helper.padChrome$.window.location.href}/import`; - const textWithNewLines = 'imported text\nnewline'; - importrequest(textWithNewLines, importurl, 'txt'); - helper.waitFor(() => expect(getinnertext()) - .to.be('imported text\nnewline\n
      \n')); - const results = exportfunc(helper.padChrome$.window.location.href); - expect(results[0][1]).to.be('imported text
      newline

      '); - expect(results[1][1]).to.be('imported text\nnewline\n\n'); - done(); - }); - xit('import a pad with newlines from html', function (done) { - const importurl = `${helper.padChrome$.window.location.href}/import`; - const htmlWithNewLines = 'htmltext
      newline'; - importrequest(htmlWithNewLines, importurl, 'html'); - helper.waitFor(() => expect(getinnertext()) - .to.be('htmltext\nnewline\n
      \n')); - const results = exportfunc(helper.padChrome$.window.location.href); - expect(results[0][1]).to.be('htmltext
      newline

      '); - expect(results[1][1]).to.be('htmltext\nnewline\n\n'); - done(); - }); - xit('import a pad with attributes from html', function (done) { - const importurl = `${helper.padChrome$.window.location.href}/import`; - const htmlWithNewLines = 'htmltext
      ' + - 'newline'; - importrequest(htmlWithNewLines, importurl, 'html'); - helper.waitFor(() => expect(getinnertext()) - .to.be('htmltext\n' + - 'newline\n
      \n')); - const results = exportfunc(helper.padChrome$.window.location.href); - expect(results[0][1]) - .to.be('htmltext
      newline

      '); - expect(results[1][1]).to.be('htmltext\nnewline\n\n'); - done(); - }); - xit('import a pad with bullets from html', function (done) { - const importurl = `${helper.padChrome$.window.location.href}/import`; - const htmlWithBullets = '
      • bullet line 1
      • ' + - '
      • bullet line 2
        • bullet2 line 1
        • ' + - '
        • bullet2 line 2
      '; - importrequest(htmlWithBullets, importurl, 'html'); - helper.waitFor(() => expect(getinnertext()).to.be( - '
      • bullet line 1
      \n' + - '
      • bullet line 2
      \n' + - '
      • bullet2 line 1
      \n' + - '
      • bullet2 line 2
      \n' + - '
      \n')); - const results = exportfunc(helper.padChrome$.window.location.href); - expect(results[0][1]).to.be( - '
      • bullet line 1
      • bullet line 2
      • ' + - '
        • bullet2 line 1
        • bullet2 line 2

      '); - expect(results[1][1]) - .to.be('\t* bullet line 1\n\t* bullet line 2\n' + - '\t\t* bullet2 line 1\n\t\t* bullet2 line 2\n\n'); - done(); - }); - xit('import a pad with bullets and newlines from html', function (done) { - const importurl = `${helper.padChrome$.window.location.href}/import`; - const htmlWithBullets = '
      • bullet line 1
      • ' + - '

      • bullet line 2
        • ' + - '
        • bullet2 line 1

        ' + - '
        • bullet2 line 2
      '; - importrequest(htmlWithBullets, importurl, 'html'); - helper.waitFor(() => expect(getinnertext()).to.be( - '
      • bullet line 1
      \n' + - '
      \n' + - '
      • bullet line 2
      \n' + - '
      • bullet2 line 1
      \n' + - '
      \n' + - '
      • bullet2 line 2
      \n' + - '
      \n')); - const results = exportfunc(helper.padChrome$.window.location.href); - expect(results[0][1]).to.be( - '
      • bullet line 1

        ' + - '
      • bullet line 2
        • bullet2 line 1
        ' + - '

        • bullet2 line 2

      '); - expect(results[1][1]).to.be( - '\t* bullet line 1\n\n\t* bullet line 2\n\t\t* bullet2 line 1\n\n\t\t* bullet2 line 2\n\n'); - done(); - }); - xit('import a pad with bullets and newlines and attributes from html', function (done) { - const importurl = `${helper.padChrome$.window.location.href}/import`; - const htmlWithBullets = '
      • bullet line 1
      • ' + - '

      • bullet line 2
      • ' + - '
        • bullet2 line 1
      ' + - '
            ' + - '
            • ' + - 'bullet4 line 2 bisu
            • ' + - 'bullet4 line 2 bs
            • ' + - '
            • bullet4 line 2 u' + - 'uis
      '; - importrequest(htmlWithBullets, importurl, 'html'); - helper.waitFor(() => expect(getinnertext()).to.be( - '
      • bullet line 1
      \n
      \n' + - '
      • bullet line 2
      \n' + - '
      • bullet2 line 1
      \n
      \n' + - '
      • ' + - 'bullet4 line 2 bisu
      \n' + - '
      • ' + - 'bullet4 line 2 bs
      \n' + - '
      • bullet4 line 2 u' + - 'uis
      \n' + - '
      \n')); - const results = exportfunc(helper.padChrome$.window.location.href); - expect(results[0][1]).to.be( - '
      • bullet line 1
      ' + - '
      • bullet line 2
        • bullet2 line 1
        • ' + - '

            • bullet4 line 2 bisu' + - '
            • bullet4 line 2 bs' + - '
            • bullet4 line 2 uuis

      '); - expect(results[1][1]).to.be( - '\t* bullet line 1\n\n\t* bullet line 2\n\t\t* bullet2 line 1\n\n\t\t\t\t* bullet4 line 2' + - ' bisu\n\t\t\t\t* bullet4 line 2 bs\n\t\t\t\t* bullet4 line 2 uuis\n\n'); - done(); - }); - xit('import a pad with nested bullets from html', function (done) { - const importurl = `${helper.padChrome$.window.location.href}/import`; - const htmlWithBullets = '
      • bullet line 1
      • ' + - '
      • bullet line 2
        • ' + - '
        • bullet2 line 1
          ' + - '
            • bullet4 line 2
            • ' + - '
            • bullet4 line 2
            • bullet4 line 2
          • bullet3 line 1
          ' + - '
      • bullet2 line 1
      '; - importrequest(htmlWithBullets, importurl, 'html'); - const oldtext = getinnertext(); - helper.waitFor(() => oldtext !== getinnertext() - // return expect(getinnertext()).to.be('\ - //
      • bullet line 1
      \n\ - //
      • bullet line 2
      \n\ - //
      • bullet2 line 1
      \n\ - //
      • bullet4 line 2
      \n\ - //
      • bullet4 line 2
      \n\ - //
      • bullet4 line 2
      \n\ - //
      \n') - ); - - const results = exportfunc(helper.padChrome$.window.location.href); - expect(results[0][1]).to.be( - '
      • bullet line 1
      • bullet line 2
      • ' + - '
        • bullet2 line 1
            • bullet4 line 2
            • ' + - '
            • bullet4 line 2
            • bullet4 line 2
          • bullet3 line 1
        ' + - '
      • bullet2 line 1

      '); - expect(results[1][1]).to.be( - '\t* bullet line 1\n\t* bullet line 2\n\t\t* bullet2 line 1\n\t\t\t\t* bullet4 line 2' + - '\n\t\t\t\t* bullet4 line 2\n\t\t\t\t* bullet4 line 2\n\t\t\t* bullet3 line 1' + - '\n\t* bullet2 line 1\n\n'); - done(); - }); - xit('import with 8 levels of bullets and newlines and attributes from html', function (done) { - const importurl = `${helper.padChrome$.window.location.href}/import`; - const htmlWithBullets = - '
      • bullet line 1
      • ' + - '

      • bullet line 2
        • ' + - 'bullet2 line 1

          ' + - '
            • ' + - 'bullet4 line 2 bisu
            • ' + - 'bullet4 line 2 bs
            • bullet4 line 2 u' + - 'uis
            • ' + - '
                    ' + - '
                    • foo
                    • ' + - 'foobar bs
                ' + - '
              • foobar
        '; - importrequest(htmlWithBullets, importurl, 'html'); - helper.waitFor(() => expect(getinnertext()).to.be( - '
        • bullet line 1
        \n
        \n' + - '
        • bullet line 2
        \n' + - '
        • bullet2 line 1
        \n
        \n' + - '
        • bullet4 line 2 bisu' + - '
        \n' + - '
        • bullet4 line 2 bs' + - '
        \n' + +describe('importexport.js', function () { + const testCases = [ + { + name: 'text with newlines', + inputText: [ + 'imported text\n', + 'newline', + ].join(''), + wantPadLines: [ + 'imported text', + 'newline', + ], + wantExportHtmlBody: [ + 'imported text
        ', + 'newline
        ', + ].join(''), + wantExportText: [ + 'imported text\n', + 'newline\n', + ].join(''), + }, + { + name: 'HTML with newlines', + inputHtmlBody: [ + 'htmltext
        ', + 'newline', + ].join(''), + wantPadLines: [ + 'htmltext', + 'newline', + '
        ', + ], + wantExportHtmlBody: [ + 'htmltext
        ', + 'newline
        ', + '
        ', + ].join(''), + wantExportText: [ + 'htmltext\n', + 'newline\n', + '\n', + ].join(''), + }, + { + name: 'HTML with attributes', + inputHtmlBody: [ + 'htmltext
        ', + 'newline', + ].join(''), + wantPadLines: [ + 'htmltext', + 'newline', + '
        ', + ], + wantExportHtmlBody: [ + 'htmltext
        ', + 'newline
        ', + '
        ', + ].join(''), + wantExportText: [ + 'htmltext\n', + 'newline\n', + '\n', + ].join(''), + }, + { + name: 'HTML with bullets', + inputHtmlBody: [ + '
          ', + '
        • bullet line 1
        • ', + '
        • bullet line 2', + '
            ', + '
          • bullet2 line 1
          • ', + '
          • bullet2 line 2
          • ', + '
          ', + '
        • ', + '
        ', + ].join(''), + wantPadLines: [ + '
        • bullet line 1
        ', + '
        • bullet line 2
        ', + '
        • bullet2 line 1
        ', + '
        • bullet2 line 2
        ', + '
        ', + ], + wantExportHtmlBody: [ + '
          ', + '
        • bullet line 1
        • ', + '
        • bullet line 2', + '
            ', + '
          • bullet2 line 1
          • ', + '
          • bullet2 line 2
          • ', + '
          ', + '
        • ', + '
        ', + '
        ', + ].map((l) => l.replace(/^\s+/, '')).join(''), + wantExportText: [ + '\t* bullet line 1\n', + '\t* bullet line 2\n', + '\t\t* bullet2 line 1\n', + '\t\t* bullet2 line 2\n', + '\n', + ].join(''), + }, + { + name: 'HTML with bullets and newlines', + inputHtmlBody: [ + '
          ', + '
        • bullet line 1
        • ', + '
        ', + '
        ', + '
          ', + '
        • bullet line 2', + '
            ', + '
          • bullet2 line 1
          • ', + '
          ', + '
        • ', + '
        ', + '
        ', + '
          ', + '
        • ', + '
            ', + '
          • bullet2 line 2
          • ', + '
          ', + '
        • ', + '
        ', + ].join(''), + wantPadLines: [ + '
        • bullet line 1
        ', + '
        ', + '
        • bullet line 2
        ', + '
        • bullet2 line 1
        ', + '
        ', + '
        • bullet2 line 2
        ', + '
        ', + ], + wantExportHtmlBody: [ + '
          ', + '
        • bullet line 1
        • ', + '
        ', + '
        ', + '
          ', + '
        • bullet line 2', + '
            ', + '
          • bullet2 line 1
          • ', + '
          ', + '
        • ', + '
        ', + '
        ', + '
          ', + '
        • ', + '
            ', + '
          • bullet2 line 2
          • ', + '
          ', + '
        • ', + '
        ', + '
        ', + ].map((l) => l.replace(/^\s+/, '')).join(''), + wantExportText: [ + '\t* bullet line 1\n', + '\n', + '\t* bullet line 2\n', + '\t\t* bullet2 line 1\n', + '\n', + '\t\t* bullet2 line 2\n', + '\n', + ].join(''), + }, + { + name: 'HTML with bullets, newlines, and attributes', + inputHtmlBody: [ + '
          ', + '
        • bullet line 1
        • ', + '
        ', + '
        ', + '
          ', + '
        • bullet line 2', + '
            ', + '
          • bullet2 line 1
          • ', + '
          ', + '
        • ', + '
        ', + '
        ', + '
          ', + '
        • ', + '
            ', + '
          • ', + '
              ', + '
            • ', + '
                ', + '
              • bullet4 line 2 bisu' + + '
              • ', + '
              • bullet4 line 2 bs
              • ', + '
              • bullet4 line 2 u' + + 'uis
              • ', + '
              ', + '
            • ', + '
            ', + '
          • ', + '
          ', + '
        • ', + '
        ', + ].join(''), + wantPadLines: [ + '
        • bullet line 1
        ', + '
        ', + '
        • bullet line 2
        ', + '
        • bullet2 line 1
        ', + '
        ', + '
        • ' + + 'bullet4 line 2 bisu
        ', + '
        • bullet4 line 2 bs' + + '
        ', '
        • bullet4 line 2 u' + - 'uis' + - '
        \n' + - '
        • foo
        \n' + - '
        • foobar bs' + - '
        \n' + - '
        • foobar
        \n' + - '
        \n')); - const results = exportfunc(helper.padChrome$.window.location.href); - expect(results[0][1]).to.be( - '
        • bullet line 1

          ' + - '
        • bullet line 2
          • bullet2 line 1
        ' + - '
              • ' + - 'bullet4 line 2 bisu
              • ' + - 'bullet4 line 2 bs
              • bullet4 line 2 u' + - 'uis
                      • foo
                      • ' + - '
                      • foobar bs
                • foobar
                • ' + - '

        '); - expect(results[1][1]).to.be( - '\t* bullet line 1\n\n\t* bullet line 2\n\t\t* ' + - 'bullet2 line 1\n\n\t\t\t\t* bullet4 line 2 bisu\n\t\t\t\t* bullet4 line 2 ' + - 'bs\n\t\t\t\t* bullet4 line 2 uuis\n\t\t\t\t\t\t\t\t* foo\n\t\t\t\t\t\t\t\t* ' + - 'foobar bs\n\t\t\t\t\t* foobar\n\n'); - done(); + 'uis
      ', + '
      ', + ], + wantExportHtmlBody: [ + '
      • bullet line 1
      ', + '
      ', + '
        ', + '
      • bullet line 2', + '
        • bullet2 line 1
        ', + '
      • ', + '
      ', + '
      ', + '
        ', + '
      • ', + '
          ', + '
        • ', + '
            ', + '
          • ', + '
              ', + '
            • bullet4 line 2 bisu
            • ', + '
            • bullet4 line 2 bs
            • ', + '
            • bullet4 line 2 uuis
            • ', + '
            ', + '
          • ', + '
          ', + '
        • ', + '
        ', + '
      • ', + '
      ', + '
      ', + ].map((l) => l.replace(/^\s+/, '')).join(''), + wantExportText: [ + '\t* bullet line 1\n', + '\n', + '\t* bullet line 2\n', + '\t\t* bullet2 line 1\n', + '\n', + '\t\t\t\t* bullet4 line 2 bisu\n', + '\t\t\t\t* bullet4 line 2 bs\n', + '\t\t\t\t* bullet4 line 2 uuis\n', + '\n', + ].join(''), + }, + { + name: 'HTML with nested bullets', + inputHtmlBody: [ + '
      • bullet line 1
      ', + '
        ', + '
      • bullet line 2', + '
          ', + '
        • bullet2 line 1
        • ', + '
        ', + '
      • ', + '
      ', + '
        ', + '
      • ', + '
          ', + '
        • ', + '
            ', + '
          • ', + '
              ', + '
            • bullet4 line 2
            • ', + '
            • bullet4 line 2
            • ', + '
            • bullet4 line 2
            • ', + '
            ', + '
          • ', + '
          • bullet3 line 1
          • ', + '
          ', + '
        • ', + '
        ', + '
      • ', + '
      ', + ].join(''), + wantPadLines: [ + '
      • bullet line 1
      ', + '
      • bullet line 2
      ', + '
      • bullet2 line 1
      ', + '
      • bullet4 line 2
      ', + '
      • bullet4 line 2
      ', + '
      • bullet4 line 2
      ', + '
      • bullet3 line 1
      ', + '
      ', + ], + wantExportHtmlBody: [ + '
        ', + '
      • bullet line 1
      • ', + '
      • bullet line 2', + '
          ', + '
        • bullet2 line 1', + '
            ', + '
          • ', + '
              ', + '
            • bullet4 line 2
            • ', + '
            • bullet4 line 2
            • ', + '
            • bullet4 line 2
            • ', + '
            ', + '
          • ', + '
          • bullet3 line 1
          • ', + '
          ', + '
        • ', + '
        ', + '
      • ', + '
      ', + '
      ', + ].map((l) => l.replace(/^\s+/, '')).join(''), + wantExportText: [ + '\t* bullet line 1\n', + '\t* bullet line 2\n', + '\t\t* bullet2 line 1\n', + '\t\t\t\t* bullet4 line 2\n', + '\t\t\t\t* bullet4 line 2\n', + '\t\t\t\t* bullet4 line 2\n', + '\t\t\t* bullet3 line 1\n', + '\n', + ].join(''), + }, + { + name: 'HTML with 8 levels of bullets, newlines, and attributes', + inputHtmlBody: [ + '
        ', + '
      • bullet line 1
      • ', + '
      ', + '
      ', + '
        ', + '
      • bullet line 2', + '
          ', + '
        • bullet2 line 1
        • ', + '
        ', + '
      • ', + '
      ', + '
      ', + '
        ', + '
      • ', + '
          ', + '
        • ', + '
            ', + '
          • ', + '
              ', + '
            • bullet4 line 2 bisu' + + '
            • ', + '
            • bullet4 line 2 bs
            • ', + '
            • bullet4 line 2 u' + + 'uis
            • ', + '
            • ', + '
                ', + '
              • ', + '
                  ', + '
                • ', + '
                    ', + '
                  • ', + '
                      ', + '
                    • foo
                    • ', + '
                    • foobar bs
                    • ', + '
                    ', + '
                  • ', + '
                  ', + '
                • ', + '
                ', + '
              • ', + '
              ', + '
            • ', + '
            • ', + '
                ', + '
              • foobar
              • ', + '
              ', + '
            • ', + '
            ', + '
          • ', + '
          ', + '
        • ', + '
        ', + '
      • ', + '
      ', + ].join(''), + wantPadLines: [ + '
      • bullet line 1
      ', + '
      ', + '
      • bullet line 2
      ', + '
      • bullet2 line 1
      ', + '
      ', + '
      • ' + + 'bullet4 line 2 bisu
      ', + '
      • bullet4 line 2 bs' + + '
      ', + '
      • bullet4 line 2 u' + + 'uis
      ', + '
      • foo
      ', + '
      • foobar bs
      ', + '
      • foobar
      ', + '
      ', + ], + wantExportHtmlBody: [ + '
        ', + '
      • bullet line 1
      • ', + '
      ', + '
      ', + '
        ', + '
      • bullet line 2', + '
          ', + '
        • bullet2 line 1
        • ', + '
        ', + '
      • ', + '
      ', + '
      ', + '
        ', + '
      • ', + '
          ', + '
        • ', + '
            ', + '
          • ', + '
              ', + '
            • bullet4 line 2 bisu
            • ', + '
            • bullet4 line 2 bs
            • ', + '
            • bullet4 line 2 uuis', + '
                ', + '
              • ', + '
                  ', + '
                • ', + '
                    ', + '
                  • ', + '
                      ', + '
                    • foo
                    • ', + '
                    • foobar bs
                    • ', + '
                    ', + '
                  • ', + '
                  ', + '
                • ', + '
                ', + '
              • ', + '
              • foobar
              • ', + '
              ', + '
            • ', + '
            ', + '
          • ', + '
          ', + '
        • ', + '
        ', + '
      • ', + '
      ', + '
      ', + ].map((l) => l.replace(/^\s+/, '')).join(''), + wantExportText: [ + '\t* bullet line 1\n', + '\n', + '\t* bullet line 2\n', + '\t\t* bullet2 line 1\n', + '\n', + '\t\t\t\t* bullet4 line 2 bisu\n', + '\t\t\t\t* bullet4 line 2 bs\n', + '\t\t\t\t* bullet4 line 2 uuis\n', + '\t\t\t\t\t\t\t\t* foo\n', + '\t\t\t\t\t\t\t\t* foobar bs\n', + '\t\t\t\t\t* foobar\n', + '\n', + ].join(''), + }, + { + name: 'HTML with ordered lists', + inputHtmlBody: [ + '
      1. number 1 line 1
      ', + '
      1. number 2 line 2
      ', + ].join(''), + wantPadLines: [ + '
      1. number 1 line 1
      ', + '
      1. number 2 line 2
      ', + '
      ', + ], + wantExportHtmlBody: [ + '
        ', + '
      1. number 1 line 1
      2. ', + '
      3. number 2 line 2
      4. ', + '
      ', + '
      ', + ].map((l) => l.replace(/^\s+/, '')).join(''), + wantExportText: [ + '\t1. number 1 line 1\n', + '\t2. number 2 line 2\n', + '\n', + ].join(''), + }, + ]; + + let confirm; + before(async function () { + this.timeout(60000); + await new Promise( + (resolve, reject) => helper.newPad((err) => err != null ? reject(err) : resolve())); + confirm = helper.padChrome$.window.confirm; + helper.padChrome$.window.confirm = () => true; + // As of 2021-02-22 a mutable FileList cannot be directly created so DataTransfer is used as a + // hack to access a mutable FileList for testing the '' element. DataTransfer + // itself is quite new so support for it is tested here. See: + // * https://github.com/whatwg/html/issues/3269 + // * https://stackoverflow.com/q/47119426 + try { + const dt = new DataTransfer(); + dt.items.add(new File(['testing'], 'file.txt', {type: 'text/plain'})); + // Supposedly all modern browsers support a settable HTMLInputElement.files property, but + // Firefox 52 complains. + helper.padChrome$('#importform input[type=file]')[0].files = dt.files; + } catch (err) { + return this.skip(); + } }); - xit('import a pad with ordered lists from html', function (done) { - const importurl = `${helper.padChrome$.window.location.href}/import`; - const htmlWithBullets = '
        ' + - '
      1. number 1 line 1
        ' + - '
      1. number 2 line 2
      '; - importrequest(htmlWithBullets, importurl, 'html'); - console.error(getinnertext()); - expect(getinnertext()).to.be( - '
      1. number 1 line 1
      \n' + - '
      1. number 2 line 2
      \n' + - '
      \n'); - const results = exportfunc(helper.padChrome$.window.location.href); - expect(results[0][1]).to.be( - '
      1. number 1 line 1
      2. ' + - '
      1. number 2 line 2
      '); - expect(results[1][1]).to.be(''); - done(); + after(async function () { + helper.padChrome$.window.confirm = confirm; }); - xit('import a pad with ordered lists and newlines from html', function (done) { - const importurl = `${helper.padChrome$.window.location.href}/import`; - const htmlWithBullets = '
        ' + - '
      1. number 9 line 1

        ' + - '
      1. number 10 line 2
        1. ' + - '
        2. number 2 times line 1

        ' + - '
        1. number 2 times line 2
      '; - importrequest(htmlWithBullets, importurl, 'html'); - expect(getinnertext()).to.be( - '
      1. number 9 line 1
      \n' + - '
      \n' + - '
      1. number 10 line 2
      2. ' + - '
      \n' + - '
      1. number 2 times line 1
      \n' + - '
      \n' + - '
      1. number 2 times line 2
      \n' + - '
      \n'); - const results = exportfunc(helper.padChrome$.window.location.href); - console.error(results); - done(); - }); - xit('import with nested ordered lists and attributes and newlines from html', function (done) { - const importurl = `${helper.padChrome$.window.location.href}/import`; - const htmlWithBullets = '
      1. ' + - 'bold strikethrough italics underline' + - ' line 1bold
      2. ' + - '

        ' + - '
      1. number 10 line 2
        1. ' + - '
        2. number 2 times line 1

      ' + - '
          ' + - '
        1. number 2 times line 2
      '; - importrequest(htmlWithBullets, importurl, 'html'); - expect(getinnertext()).to.be( - '
      1. ' + - 'bold strikethrough italics underline' + - ' line 1bold
      \n' + - '
      \n' + - '
      1. number 10 line 2
      \n' + - '
      1. ' + - 'number 2 times line 1
      \n' + - '
      \n' + - '
      1. number 2 times line 2
      \n' + - '
      \n'); - const results = exportfunc(helper.padChrome$.window.location.href); - console.error(results); - done(); + + beforeEach(async function () { + const popup = helper.padChrome$('#import_export'); + const isVisible = () => popup.hasClass('popup-show'); + if (isVisible()) return; + const button = helper.padChrome$('button[data-l10n-id="pad.toolbar.import_export.title"]'); + button.click(); + await helper.waitForPromise(isVisible); }); + + const docToHtml = (() => { + const s = new XMLSerializer(); + return (doc) => s.serializeToString(doc); + })(); + + const htmlToDoc = (() => { + const p = new DOMParser(); + return (html) => p.parseFromString(html, 'text/html'); + })(); + + const htmlBodyToDoc = (htmlBody) => { + const doc = document.implementation.createHTMLDocument(); + $('body', doc).html(htmlBody); + return doc; + }; + + for (const tc of testCases) { + describe(tc.name, function () { + it('import', async function () { + const ext = tc.inputHtmlBody ? 'html' : 'txt'; + const contents = ext === 'html' ? docToHtml(htmlBodyToDoc(tc.inputHtmlBody)) : tc.inputText; + // DataTransfer is used as a hacky way to get a mutable FileList. For details, see: + // https://stackoverflow.com/q/47119426 + const dt = new DataTransfer(); + dt.items.add(new File([contents], `file.${ext}`, {type: 'text/plain'})); + const form = helper.padChrome$('#importform'); + form.find('input[type=file]')[0].files = dt.files; + form.find('#importsubmitinput').submit(); + try { + await helper.waitForPromise(() => { + const got = helper.linesDiv(); + if (got.length !== tc.wantPadLines.length) return false; + for (let i = 0; i < got.length; i++) { + const gotDiv = $('
      ').html(got[i].html()); + const wantDiv = $('
      ').html(tc.wantPadLines[i]); + if (!gotDiv[0].isEqualNode(wantDiv[0])) return false; + } + return true; + }); + } catch (err) { + const formatLine = (l) => ` ${JSON.stringify(l)}`; + const g = helper.linesDiv().map((div) => formatLine(div.html())).join('\n'); + const w = tc.wantPadLines.map(formatLine).join('\n'); + throw new Error(`Import failed. Got pad lines:\n${g}\nWant pad lines:\n${w}`); + } + }); + + it('export to HTML', async function () { + const link = helper.padChrome$('#exporthtmla').attr('href'); + const url = new URL(link, helper.padChrome$.window.location.href).href; + const gotHtml = await $.ajax({url, dataType: 'html'}); + const gotBody = $('body', htmlToDoc(gotHtml)); + gotBody.html(gotBody.html().replace(/^\s+|\s+$/g, '')); + const wantBody = $('body', htmlBodyToDoc(tc.wantExportHtmlBody)); + if (!gotBody[0].isEqualNode(wantBody[0])) { + throw new Error(`Got exported HTML body:\n ${JSON.stringify(gotBody.html())}\n` + + `Want HTML body:\n ${JSON.stringify(wantBody.html())}`); + } + }); + + it('export to text', async function () { + const link = helper.padChrome$('#exportplaina').attr('href'); + const url = new URL(link, helper.padChrome$.window.location.href).href; + const got = await $.ajax({url, dataType: 'text'}); + expect(got).to.be(tc.wantExportText); + }); + }); + } });