diff --git a/app/assets/javascripts/discourse/app/models/composer.js b/app/assets/javascripts/discourse/app/models/composer.js index 8aa68daaa69..e7911545a9c 100644 --- a/app/assets/javascripts/discourse/app/models/composer.js +++ b/app/assets/javascripts/discourse/app/models/composer.js @@ -929,6 +929,7 @@ const Composer = RestModel.extend({ editPost(opts) { const post = this.post; + const oldRaw = post.raw; const oldCooked = post.cooked; let promise = Promise.resolve(); @@ -970,16 +971,14 @@ const Composer = RestModel.extend({ this.set("composeState", SAVING); const rollback = throwAjaxError((error) => { - post.setProperties({ cooked: oldCooked, staged: false }); - this.appEvents.trigger("post-stream:refresh", { id: post.id }); - + post.setProperties({ raw: oldRaw, cooked: oldCooked }); this.set("composeState", OPEN); if (error.jqXHR && error.jqXHR.status === 409) { this.set("editConflict", true); } }); - post.setProperties({ cooked: props.cooked, staged: true }); + post.setProperties({ raw: props.raw, cooked: props.cooked, staged: true }); this.appEvents.trigger("post-stream:refresh", { id: post.id }); return promise diff --git a/app/assets/javascripts/discourse/tests/acceptance/composer-edit-conflict-test.js b/app/assets/javascripts/discourse/tests/acceptance/composer-edit-conflict-test.js index 96f970237a0..6eb7be82355 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/composer-edit-conflict-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/composer-edit-conflict-test.js @@ -14,26 +14,23 @@ acceptance("Composer - Edit conflict", function (needs) { }); }); - QUnit.skip( - "Edit a post that causes an edit conflict", - async function (assert) { - await visit("/t/internationalization-localization/280"); - await click(".topic-post:nth-of-type(1) button.show-more-actions"); - await click(".topic-post:nth-of-type(1) button.edit"); - await fillIn(".d-editor-input", "this will 409"); - await click("#reply-control button.create"); - assert.equal( - queryAll("#reply-control button.create").text().trim(), - I18n.t("composer.overwrite_edit"), - "it shows the overwrite button" - ); - assert.ok( - queryAll("#draft-status .d-icon-user-edit"), - "error icon should be there" - ); - await click(".modal .btn-primary"); - } - ); + test("Edit a post that causes an edit conflict", async function (assert) { + await visit("/t/internationalization-localization/280"); + await click(".topic-post:nth-of-type(1) button.show-more-actions"); + await click(".topic-post:nth-of-type(1) button.edit"); + await fillIn(".d-editor-input", "this will 409"); + await click("#reply-control button.create"); + assert.equal( + queryAll("#reply-control button.create").text().trim(), + I18n.t("composer.overwrite_edit"), + "it shows the overwrite button" + ); + assert.ok( + queryAll("#draft-status .d-icon-user-edit"), + "error icon should be there" + ); + await click(".modal .btn-primary"); + }); test("Should not send originalText when posting a new reply", async function (assert) { await visit("/t/internationalization-localization/280"); diff --git a/app/assets/javascripts/discourse/tests/acceptance/composer-test.js b/app/assets/javascripts/discourse/tests/acceptance/composer-test.js index 5fc43fee68a..c499f1a7481 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/composer-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/composer-test.js @@ -348,15 +348,25 @@ acceptance("Composer", function (needs) { ); }); - QUnit.skip("Editing a post stages new content", async function (assert) { + test("Editing a post stages new content", async function (assert) { await visit("/t/internationalization-localization/280"); await click(".topic-post:nth-of-type(1) button.show-more-actions"); await click(".topic-post:nth-of-type(1) button.edit"); await fillIn(".d-editor-input", "will return empty json"); await fillIn("#reply-title", "This is the new text for the title"); - await click("#reply-control button.create"); + // when this promise resolves, the request had already started because + // this promise will be resolved by the pretender + const promise = new Promise((resolve) => { + window.resolveLastPromise = resolve; + }); + + // click to trigger the save, but wait until the request starts + click("#reply-control button.create"); + await promise; + + // at this point, request is in flight, so post is staged assert.equal(count(".topic-post.staged"), 1); assert.ok( find(".topic-post:nth-of-type(1)")[0].className.includes("staged") @@ -365,28 +375,31 @@ acceptance("Composer", function (needs) { find(".topic-post.staged .cooked").text().trim(), "will return empty json" ); + + // finally, finish request and wait for last render + window.resolveLastPromise(); + await visit("/t/internationalization-localization/280"); + + assert.equal(count(".topic-post.staged"), 0); }); - QUnit.skip( - "Editing a post can rollback to old content", - async function (assert) { - await visit("/t/internationalization-localization/280"); - await click(".topic-post:nth-of-type(1) button.show-more-actions"); - await click(".topic-post:nth-of-type(1) button.edit"); + test("Editing a post can rollback to old content", async function (assert) { + await visit("/t/internationalization-localization/280"); + await click(".topic-post:nth-of-type(1) button.show-more-actions"); + await click(".topic-post:nth-of-type(1) button.edit"); - await fillIn(".d-editor-input", "this will 409"); - await fillIn("#reply-title", "This is the new text for the title"); - await click("#reply-control button.create"); + await fillIn(".d-editor-input", "this will 409"); + await fillIn("#reply-title", "This is the new text for the title"); + await click("#reply-control button.create"); - assert.ok(!exists(".topic-post.staged")); - assert.equal( - find(".topic-post .cooked")[0].innerText, - "Any plans to support localization of UI elements, so that I (for example) could set up a completely German speaking forum?" - ); + assert.ok(!exists(".topic-post.staged")); + assert.equal( + find(".topic-post .cooked")[0].innerText, + "Any plans to support localization of UI elements, so that I (for example) could set up a completely German speaking forum?" + ); - await click(".bootbox.modal .btn-primary"); - } - ); + await click(".bootbox.modal .btn-primary"); + }); test("Composer can switch between edits", async function (assert) { await visit("/t/this-is-a-test-topic/9"); diff --git a/app/assets/javascripts/discourse/tests/helpers/create-pretender.js b/app/assets/javascripts/discourse/tests/helpers/create-pretender.js index 2b843d62672..b312f02e25a 100644 --- a/app/assets/javascripts/discourse/tests/helpers/create-pretender.js +++ b/app/assets/javascripts/discourse/tests/helpers/create-pretender.js @@ -1,6 +1,7 @@ import Pretender from "pretender"; import User from "discourse/models/user"; import getURL from "discourse-common/lib/get-url"; +import { Promise } from "rsvp"; export function parsePostData(query) { const result = {}; @@ -479,12 +480,15 @@ export function applyDefaultHandlers(pretender) { pretender.put("/posts/:post_id/recover", success); pretender.get("/posts/:post_id/expand-embed", success); - pretender.put("/posts/:post_id", (request) => { + pretender.put("/posts/:post_id", async (request) => { const data = parsePostData(request.requestBody); if (data.post.raw === "this will 409") { return response(409, { errors: ["edit conflict"] }); } else if (data.post.raw === "will return empty json") { - return response(200, {}); + window.resolveLastPromise(); + return new Promise((resolve) => { + window.resolveLastPromise = resolve; + }).then(() => response(200, {})); } data.post.id = request.params.post_id; data.post.version = 2;