From c53b798267b2ce42b2fdb8c41981e3e80d3e9a9d Mon Sep 17 00:00:00 2001 From: Thanh Dodeur Date: Thu, 5 Nov 2020 08:51:31 +0000 Subject: [PATCH] [FIX] mail: prevents traceback on attachment delete during upload MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Before this commit, removing attachments that are being uploaded could lead to a traceback if the removed attachment was still awaiting for the upload of another attachment. part of task-2363522 closes odoo/odoo#63164 X-original-commit: d345ab808d1261953ee9c588d1cb5fe2571d3e69 Signed-off-by: Alexandre Kühn (aku) --- .../src/components/composer/composer_tests.js | 52 +++++++++++++++++++ .../components/file_uploader/file_uploader.js | 6 ++- 2 files changed, 57 insertions(+), 1 deletion(-) diff --git a/addons/mail/static/src/components/composer/composer_tests.js b/addons/mail/static/src/components/composer/composer_tests.js index 81a1e9507df..c4fec2f8169 100644 --- a/addons/mail/static/src/components/composer/composer_tests.js +++ b/addons/mail/static/src/components/composer/composer_tests.js @@ -2154,6 +2154,58 @@ QUnit.test("mentioned partners should not be notified if they are not member of assert.verifySteps(['message_post'], "the message should be posted"); }); +QUnit.test('[technical] does not crash when an attachment is removed before its upload starts', async function (assert) { + // Uploading multiple files uploads attachments one at a time, this test + // ensures that there is no crash when an attachment is destroyed before its + // upload started. + assert.expect(1); + + // Promise to block attachment uploading + const uploadPromise = makeTestPromise(); + await this.start({ + async mockFetch(resource) { + const _super = this._super.bind(this, ...arguments); + if (resource === '/web/binary/upload_attachment') { + await uploadPromise; + } + return _super(); + }, + }); + const composer = this.env.models['mail.composer'].create(); + await this.createComposerComponent(composer); + const file1 = await createFile({ + name: 'text1.txt', + content: 'hello, world', + contentType: 'text/plain', + }); + const file2 = await createFile({ + name: 'text2.txt', + content: 'hello, world', + contentType: 'text/plain', + }); + await afterNextRender(() => + inputFiles( + document.querySelector('.o_FileUploader_input'), + [file1, file2] + ) + ); + await afterNextRender(() => { + Array.from(document.querySelectorAll('div')) + .find(el => el.textContent === 'text2.txt') + .closest('.o_Attachment') + .querySelector('.o_Attachment_asideItemUnlink') + .click(); + } + ); + // Simulates the completion of the upload of the first attachment + uploadPromise.resolve(); + assert.containsOnce( + document.body, + '.o_Attachment:contains("text1.txt")', + "should only have the first attachment after cancelling the second attachment" + ); +}); + }); }); }); diff --git a/addons/mail/static/src/components/file_uploader/file_uploader.js b/addons/mail/static/src/components/file_uploader/file_uploader.js index efa0026842d..8718f819e11 100644 --- a/addons/mail/static/src/components/file_uploader/file_uploader.js +++ b/addons/mail/static/src/components/file_uploader/file_uploader.js @@ -101,7 +101,11 @@ class FileUploader extends Component { attachment.isTemporary && attachment.filename === file.name ); - + if (!uploadingAttachment) { + // Uploading attachment no longer exists. + // This happens when an uploading attachment is being deleted by user. + continue; + } try { const response = await this.env.browser.fetch('/web/binary/upload_attachment', { method: 'POST',