summaryrefslogtreecommitdiff
path: root/addons/mail/static/tests/document_thread_window_tests.js
diff options
context:
space:
mode:
authorAlexandre Kühn <aku@odoo.com>2019-08-29 16:28:07 +0000
committerAlexandre Kühn <aku@odoo.com>2019-09-03 08:11:27 +0000
commit40b57ca824e967a9221f7834e4c9b3db7a4849d0 (patch)
treecb11f94d3c993e83e93a386914075d9e8e8a3cde /addons/mail/static/tests/document_thread_window_tests.js
parent7bdcef9c1c4d42f39302403e1c5e56682788022c (diff)
[FIX] bus, mail: correctly synchronize document chat windows
Before this commit, there could be an infinite loop when changing the chat window state of a document chat window. This is caused when mutiple tabs overwrite the chat window state with a different value everytime, resulting to an infinite loop. Accross multiple tabs, `setItem` and `onStorage` are not synchronous. That's why tabs should communicate through local storage events instead of actual value in the local storage. To illustrate the issue, suppose there are 2 tabs (T1 and T2) with one document chat windows (C) and the following user interactions: - T1 and T2 both have C open - on T1, user folds C - on T2, user folds C Now let's add an example of local storage (LS) logics that could apply from above example: - T1 and T2 both have C open - on T1, user folds C [1] T1 writes 'C folded' in LS - on T2, user folds C [2] T2 writes 'C folded' in LS [3] T2 detects 'C folded' in LS (from [1]) => T2 writes 'C folded' in LS [4] T1 detects 'C folded' in LS (from [2]) => T1 writes 'C folded' in LS [5] T1 detects 'C folded' in LS (from [3]) => T1 writes 'C folded' in LS [6] T2 detects 'C folded' in LS (from [4]) => T2 writes 'C folded' in LS etc... This scenario could have been easily prevented by not writing on local storage when the chat window state has not changed. However, this wouldn't fix this scenario that also introduces an infinite loop: - T1 and T2 both have C open - on T1, user folds C [1] T1 writes 'C folded' in LS - on T2, user folds C [2] T2 writes 'C folded' in LS - on T2, user unfolds C [3] T2 writes 'C unfolded' in LS [4] T2 detects 'C folded' in LS (from [1]) => T2 writes 'C folded' in LS [5] T1 detects 'C unfolded' in LS (from [3]) => T1 writes 'C unfolded' in LS [6] T2 detects 'C unfolded' in LS (from [5]) => T2 writes 'C unfolded' in LS [7] T1 detects 'C folded' in LS (from [4]) => T1 writes 'C folded' in LS [8] T2 detects 'C folded' in LS (from [7]) => T2 writes 'C folded' in LS [9] T1 detects 'C unfolded' in LS (from [6]) => T1 writes 'C folded' in LS etc... This commit fixes the infinite loop issue: - by turning local storage read during cross-tab communication into local storage event read instead. This should prevent race conditions based on read/write operations in local, since their order is not guaranteed accros tabs. - by isolating document chat window state to their own local storage entry. This should prevent a tab from notifying a chat window state that it didn't change, which may also result in an infinite loop. Some tests were adapted from the changes above. Also, some tests did pass thanks to local storage being mocked by a ram storage: the handler `_onStorage` should have been called, but it didn't because it was registered on the actual local storage instead of the ram storage. In order to make tests pass again, the following additional changes were required: - Cross-tab bus service now exports the unique tab ID with `getTabId`. - document thread entries in local storage now track the tab ID, so that self-tab ignore their own local storage writes. Task-Id 2034997 Closes #36177
Diffstat (limited to 'addons/mail/static/tests/document_thread_window_tests.js')
-rw-r--r--addons/mail/static/tests/document_thread_window_tests.js20
1 files changed, 13 insertions, 7 deletions
diff --git a/addons/mail/static/tests/document_thread_window_tests.js b/addons/mail/static/tests/document_thread_window_tests.js
index bdab46e91ef..fe2b31b2811 100644
--- a/addons/mail/static/tests/document_thread_window_tests.js
+++ b/addons/mail/static/tests/document_thread_window_tests.js
@@ -201,7 +201,7 @@ QUnit.test('post messages in a document thread window', function (assert) {
testUtils.intercept(messagingMenu, 'call_service', function (ev) {
if (ev.data.service === 'local_storage' && ev.data.method === 'setItem' &&
ev.data.args[0] === 'mail.document_threads_last_message') {
- assert.deepEqual(ev.data.args[1], newMessage,
+ assert.deepEqual(ev.data.args[1].messageData, newMessage,
"should write sent message in local storage, to share info with other tabs");
}
}, true);
@@ -229,7 +229,7 @@ QUnit.test('post messages in a document thread window', function (assert) {
});
QUnit.test('open, fold, unfold and close a document thread window', function (assert) {
- assert.expect(8);
+ assert.expect(24);
var messagingMenu = new MessagingMenu();
testUtils.addMockEnvironment(messagingMenu, {
@@ -239,7 +239,13 @@ QUnit.test('open, fold, unfold and close a document thread window', function (as
});
testUtils.intercept(messagingMenu, 'call_service', function (ev) {
if (ev.data.service === 'local_storage' && ev.data.method === 'setItem') {
- assert.step(ev.data.args);
+ const key = ev.data.args[0];
+ const state = ev.data.args[1].state;
+ assert.strictEqual(key, 'mail.document_threads_state/some.res.model_1');
+ assert.ok(state);
+ assert.ok(state.name);
+ assert.ok(state.windowState);
+ assert.step(`${key}: { name: "${state.name}", windowState: '${state.windowState}' }`);
}
}, true);
messagingMenu.appendTo($('#qunit-fixture'));
@@ -262,10 +268,10 @@ QUnit.test('open, fold, unfold and close a document thread window', function (as
$('.o_thread_window .o_thread_window_close').click();
assert.verifySteps([
- ['mail.document_threads_state', {"some.res.model_1": {"name": "Some Record", "windowState": "open"}}],
- ['mail.document_threads_state', {"some.res.model_1": {"name": "Some Record", "windowState": "folded"}}],
- ['mail.document_threads_state', {"some.res.model_1": {"name": "Some Record", "windowState": "open"}}],
- ['mail.document_threads_state', {"some.res.model_1": {"name": "Some Record", "windowState": "closed"}}],
+ `mail.document_threads_state/some.res.model_1: { name: "Some Record", windowState: 'open' }`,
+ `mail.document_threads_state/some.res.model_1: { name: "Some Record", windowState: 'folded' }`,
+ `mail.document_threads_state/some.res.model_1: { name: "Some Record", windowState: 'open' }`,
+ `mail.document_threads_state/some.res.model_1: { name: "Some Record", windowState: 'closed' }`,
]);
messagingMenu.destroy();