diff --git a/test/javascripts/acceptance/admin-suspend-user-test.js.es6 b/test/javascripts/acceptance/admin-suspend-user-test.js.es6
index 3107ac9eab7..40da286a81c 100644
--- a/test/javascripts/acceptance/admin-suspend-user-test.js.es6
+++ b/test/javascripts/acceptance/admin-suspend-user-test.js.es6
@@ -50,8 +50,8 @@ QUnit.test("suspend, then unsuspend a user", async assert => {
     "disabled by default"
   );
 
-  suspendUntilCombobox.expandAwait();
-  suspendUntilCombobox.selectRowByValueAwait("tomorrow");
+  await suspendUntilCombobox.expandAwait();
+  await suspendUntilCombobox.selectRowByValueAwait("tomorrow");
 
   await fillIn(".suspend-reason", "for breaking the rules");
   await fillIn(".suspend-message", "this is an email reason why");
diff --git a/test/javascripts/acceptance/category-chooser-test.js.es6 b/test/javascripts/acceptance/category-chooser-test.js.es6
index 24a576cce1c..d9aabcb9e01 100644
--- a/test/javascripts/acceptance/category-chooser-test.js.es6
+++ b/test/javascripts/acceptance/category-chooser-test.js.es6
@@ -13,7 +13,7 @@ QUnit.test("does not display uncategorized if not allowed", async assert => {
   await visit("/");
   await click("#create-topic");
 
-  categoryChooser.expandAwait();
+  await categoryChooser.expandAwait();
 
   assert.ok(categoryChooser.rowByIndex(0).name() !== "uncategorized");
 });
diff --git a/test/javascripts/acceptance/category-edit-security-test.js.es6 b/test/javascripts/acceptance/category-edit-security-test.js.es6
index 4efc1897ea2..158de71336f 100644
--- a/test/javascripts/acceptance/category-edit-security-test.js.es6
+++ b/test/javascripts/acceptance/category-edit-security-test.js.es6
@@ -33,7 +33,7 @@ QUnit.test("removing a permission", async assert => {
   await click(".edit-category");
   await click("li.edit-category-security a");
   await click(".edit-category-tab-security .edit-permission");
-  availableGroups.expand();
+  await availableGroups.expandAwait();
 
   assert.notOk(
     availableGroups.rowByValue("everyone").exists(),
@@ -43,7 +43,7 @@ QUnit.test("removing a permission", async assert => {
   await click(
     ".edit-category-tab-security .permission-list li:first-of-type .remove-permission"
   );
-  availableGroups.expand();
+  await availableGroups.expandAwait();
 
   assert.ok(
     availableGroups.rowByValue("everyone").exists(),
@@ -60,8 +60,10 @@ QUnit.test("adding a permission", async assert => {
   await click(".edit-category");
   await click("li.edit-category-security a");
   await click(".edit-category-tab-security .edit-permission");
-  availableGroups.expand().selectRowByValue("staff");
-  permissionSelector.expand().selectRowByValue("2");
+  await availableGroups.expandAwait();
+  await availableGroups.selectRowByValueAwait("staff");
+  await permissionSelector.expandAwait();
+  await permissionSelector.selectRowByValueAwait("2");
   await click(".edit-category-tab-security .add-permission");
 
   const $addedPermissionItem = find(
@@ -93,7 +95,8 @@ QUnit.test("adding a previously removed permission", async assert => {
     "it removes the permission from the list"
   );
 
-  availableGroups.expand().selectRowByValue("everyone");
+  await availableGroups.expandAwait();
+  await availableGroups.selectRowByValueAwait("everyone");
   await click(".edit-category-tab-security .add-permission");
 
   assert.equal(
diff --git a/test/javascripts/acceptance/category-edit-test.js.es6 b/test/javascripts/acceptance/category-edit-test.js.es6
index 8978edd2fba..8f27724bb1e 100644
--- a/test/javascripts/acceptance/category-edit-test.js.es6
+++ b/test/javascripts/acceptance/category-edit-test.js.es6
@@ -78,7 +78,8 @@ QUnit.test("Subcategory list settings", async assert => {
   );
 
   await click(".edit-category-general");
-  categoryChooser.expand().selectRowByValue(3);
+  await categoryChooser.expandAwait();
+  await categoryChooser.selectRowByValueAwait(3);
 
   await click(".edit-category-settings a");
 
diff --git a/test/javascripts/acceptance/composer-test.js.es6 b/test/javascripts/acceptance/composer-test.js.es6
index ccbe710612f..274d4e1642e 100644
--- a/test/javascripts/acceptance/composer-test.js.es6
+++ b/test/javascripts/acceptance/composer-test.js.es6
@@ -419,7 +419,7 @@ QUnit.test("Disable body until category is selected", async assert => {
 
   await fillIn(".d-editor-input", "Now I can type stuff");
   await categoryChooser.expandAwait();
-  await categoryChooser.selectRowByValue("__none__");
+  await categoryChooser.selectRowByValueAwait("__none__");
 
   assert.ok(
     find(".d-editor-textarea-wrapper.disabled").length === 0,
diff --git a/test/javascripts/acceptance/forgot-password-test.js.es6 b/test/javascripts/acceptance/forgot-password-test.js.es6
index 2107bbacf25..773f5709138 100644
--- a/test/javascripts/acceptance/forgot-password-test.js.es6
+++ b/test/javascripts/acceptance/forgot-password-test.js.es6
@@ -3,101 +3,86 @@ import { acceptance } from "helpers/qunit-helpers";
 let userFound = false;
 
 acceptance("Forgot password", {
-  beforeEach() {
-    const response = object => {
-      return [200, { "Content-Type": "application/json" }, object];
-    };
-
-    // prettier-ignore
-    server.post("/session/forgot_password", () => { // eslint-disable-line no-undef
-      return response({ user_found: userFound });
+  pretend(server, helper) {
+    server.post("/session/forgot_password", () => {
+      return helper.response({
+        user_found: userFound
+      });
     });
   }
 });
 
-QUnit.test("requesting password reset", assert => {
-  visit("/");
-  click("header .login-button");
-  click("#forgot-password-link");
+QUnit.test("requesting password reset", async assert => {
+  await visit("/");
+  await click("header .login-button");
+  await click("#forgot-password-link");
 
-  andThen(() => {
-    assert.equal(
-      find(".forgot-password-reset").attr("disabled"),
-      "disabled",
-      "it should disable the button until the field is filled"
-    );
-  });
+  assert.equal(
+    find(".forgot-password-reset").attr("disabled"),
+    "disabled",
+    "it should disable the button until the field is filled"
+  );
 
-  fillIn("#username-or-email", "someuser");
-  click(".forgot-password-reset");
+  await fillIn("#username-or-email", "someuser");
+  await click(".forgot-password-reset");
 
-  andThen(() => {
-    assert.equal(
-      find(".alert-error")
-        .html()
-        .trim(),
-      I18n.t("forgot_password.complete_username_not_found", {
-        username: "someuser"
-      }),
-      "it should display an error for an invalid username"
-    );
-  });
+  assert.equal(
+    find(".alert-error")
+      .html()
+      .trim(),
+    I18n.t("forgot_password.complete_username_not_found", {
+      username: "someuser"
+    }),
+    "it should display an error for an invalid username"
+  );
 
-  fillIn("#username-or-email", "someuser@gmail.com");
-  click(".forgot-password-reset");
+  await fillIn("#username-or-email", "someuser@gmail.com");
+  await click(".forgot-password-reset");
 
-  andThen(() => {
-    assert.equal(
-      find(".alert-error")
-        .html()
-        .trim(),
-      I18n.t("forgot_password.complete_email_not_found", {
-        email: "someuser@gmail.com"
-      }),
-      "it should display an error for an invalid email"
-    );
-  });
+  assert.equal(
+    find(".alert-error")
+      .html()
+      .trim(),
+    I18n.t("forgot_password.complete_email_not_found", {
+      email: "someuser@gmail.com"
+    }),
+    "it should display an error for an invalid email"
+  );
 
-  fillIn("#username-or-email", "someuser");
+  await fillIn("#username-or-email", "someuser");
 
-  andThen(() => {
-    userFound = true;
-  });
+  userFound = true;
 
-  click(".forgot-password-reset");
+  await click(".forgot-password-reset");
 
-  andThen(() => {
-    assert.notOk(
-      exists(find(".alert-error")),
-      "it should remove the flash error when succeeding"
-    );
+  assert.notOk(
+    exists(find(".alert-error")),
+    "it should remove the flash error when succeeding"
+  );
 
-    assert.equal(
-      find(".modal-body")
-        .html()
-        .trim(),
-      I18n.t("forgot_password.complete_username_found", {
-        username: "someuser"
-      }),
-      "it should display a success message for a valid username"
-    );
-  });
+  assert.equal(
+    find(".modal-body")
+      .html()
+      .trim(),
+    I18n.t("forgot_password.complete_username_found", {
+      username: "someuser"
+    }),
+    "it should display a success message for a valid username"
+  );
 
-  visit("/");
-  click("header .login-button");
-  click("#forgot-password-link");
-  fillIn("#username-or-email", "someuser@gmail.com");
-  click(".forgot-password-reset");
+  await visit("/");
+  await click("header .login-button");
+  await click("#forgot-password-link");
+  await fillIn("#username-or-email", "someuser@gmail.com");
+  await click(".forgot-password-reset");
 
-  andThen(() => {
-    assert.equal(
-      find(".modal-body")
-        .html()
-        .trim(),
-      I18n.t("forgot_password.complete_email_found", {
-        email: "someuser@gmail.com"
-      }),
-      "it should display a success message for a valid email"
-    );
-  });
+  assert.equal(
+    find(".modal-body")
+      .html()
+      .trim(),
+    I18n.t("forgot_password.complete_email_found", {
+      email: "someuser@gmail.com"
+    }),
+    "it should display a success message for a valid email"
+  );
 });
diff --git a/test/javascripts/acceptance/group-manage-logs-test.js.es6 b/test/javascripts/acceptance/group-manage-logs-test.js.es6
index a600e489b5e..ab23cfaea47 100644
--- a/test/javascripts/acceptance/group-manage-logs-test.js.es6
+++ b/test/javascripts/acceptance/group-manage-logs-test.js.es6
@@ -2,14 +2,9 @@ import { acceptance } from "helpers/qunit-helpers";
 
 acceptance("Group logs", {
   loggedIn: true,
-  beforeEach() {
-    const response = object => {
-      return [200, { "Content-Type": "application/json" }, object];
-    };
-
-    // prettier-ignore
-    server.get("/groups/snorlax.json", () => { // eslint-disable-line no-undef
-      return response({
+  pretend(server, helper) {
+    server.get("/groups/snorlax.json", () => {
+      return helper.response({
         group: {
           id: 41,
           automatic: false,
@@ -37,10 +32,9 @@ acceptance("Group logs", {
     });
 
     // Workaround while awaiting https://github.com/tildeio/route-recognizer/issues/53
-    // prettier-ignore
-    server.get("/groups/snorlax/logs.json", request => { // eslint-disable-line no-undef
+    server.get("/groups/snorlax/logs.json", request => {
       if (request.queryParams["filters[action]"]) {
-        return response({
+        return helper.response({
           logs: [
             {
               action: "change_group_setting",
@@ -59,7 +53,7 @@ acceptance("Group logs", {
           all_loaded: true
         });
       } else {
-        return response({
+        return helper.response({
           logs: [
             {
               action: "change_group_setting",
@@ -99,21 +93,16 @@ acceptance("Group logs", {
   }
 });
 
-QUnit.test("Browsing group logs", assert => {
-  visit("/groups/snorlax/manage/logs");
+QUnit.test("Browsing group logs", async assert => {
+  await visit("/groups/snorlax/manage/logs");
+  assert.ok(
+    find("tr.group-manage-logs-row").length === 2,
+    "it should display the right number of logs"
+  );
 
-  andThen(() => {
-    assert.ok(
-      find("tr.group-manage-logs-row").length === 2,
-      "it should display the right number of logs"
-    );
-    click(find(".group-manage-logs-row button")[0]);
-  });
-
-  andThen(() => {
-    assert.ok(
-      find("tr.group-manage-logs-row").length === 1,
-      "it should display the right number of logs"
-    );
-  });
+  await click(find(".group-manage-logs-row button")[0]);
+  assert.ok(
+    find("tr.group-manage-logs-row").length === 1,
+    "it should display the right number of logs"
+  );
 });
diff --git a/test/javascripts/acceptance/group-test.js.es6 b/test/javascripts/acceptance/group-test.js.es6
index 7cbffeb72e1..a5a28125e80 100644
--- a/test/javascripts/acceptance/group-test.js.es6
+++ b/test/javascripts/acceptance/group-test.js.es6
@@ -3,6 +3,13 @@ import { acceptance, logIn } from "helpers/qunit-helpers";
 acceptance("Group", {
   settings: {
     enable_group_directory: true
+  },
+  pretend(server, helper) {
+    server.post("/groups/Macdonald/request_membership", () => {
+      return helper.response({
+        relative_url: "/t/internationalization-localization/280"
+      });
+    });
   }
 });
 
@@ -72,76 +79,59 @@ QUnit.test("Anonymous Viewing Group", async assert => {
   );
 });
 
-QUnit.test("Anonymous Viewing Automatic Group", assert => {
-  visit("/groups/moderators");
+QUnit.test("Anonymous Viewing Automatic Group", async assert => {
+  await visit("/groups/moderators");
 
-  andThen(() => {
-    assert.equal(
-      count(".nav-pills li a[title='Manage']"),
-      0,
-      "it deos not show group messages navigation link"
-    );
-  });
+  assert.equal(
+    count(".nav-pills li a[title='Manage']"),
+    0,
+    "it deos not show group messages navigation link"
+  );
 });
 
-QUnit.test("User Viewing Group", assert => {
+QUnit.test("User Viewing Group", async assert => {
   logIn();
   Discourse.reset();
 
-  visit("/groups");
-  click(".group-index-request");
+  await visit("/groups");
+  await click(".group-index-request");
 
-  // prettier-ignore
-  server.post("/groups/Macdonald/request_membership", () => { // eslint-disable-line no-undef
-    return [
-      200,
-      { "Content-Type": "application/json" },
-      { relative_url: "/t/internationalization-localization/280" }
-    ];
-  });
+  assert.equal(
+    find(".modal-header")
+      .text()
+      .trim(),
+    I18n.t("groups.membership_request.title", { group_name: "Macdonald" })
+  );
 
-  andThen(() => {
-    assert.equal(
-      find(".modal-header")
-        .text()
-        .trim(),
-      I18n.t("groups.membership_request.title", { group_name: "Macdonald" })
-    );
+  assert.equal(
+    find(".request-group-membership-form textarea").val(),
+    "Please add me"
+  );
 
-    assert.equal(
-      find(".request-group-membership-form textarea").val(),
-      "Please add me"
-    );
-  });
+  await click(".modal-footer .btn-primary");
 
-  click(".modal-footer .btn-primary");
+  assert.equal(
+    find(".fancy-title")
+      .text()
+      .trim(),
+    "Internationalization / localization"
+  );
 
-  andThen(() => {
-    assert.equal(
-      find(".fancy-title")
-        .text()
-        .trim(),
-      "Internationalization / localization"
-    );
-  });
+  await visit("/groups/discourse");
 
-  visit("/groups/discourse");
+  await click(".group-message-button");
 
-  click(".group-message-button");
-
-  andThen(() => {
-    assert.ok(count("#reply-control") === 1, "it opens the composer");
-    assert.equal(
-      find(".ac-wrap .item").text(),
-      "discourse",
-      "it prefills the group name"
-    );
-  });
+  assert.ok(count("#reply-control") === 1, "it opens the composer");
+  assert.equal(
+    find(".ac-wrap .item").text(),
+    "discourse",
+    "it prefills the group name"
+  );
 });
 
 QUnit.test(
   "Admin viewing group messages when there are no messages",
-  assert => {
+  async assert => {
     // prettier-ignore
     server.get("/topics/private-messages-group/eviltrout/discourse.json", () => { // eslint-disable-line no-undef
       return response({ topic_list: { topics: [] } });
@@ -150,23 +140,21 @@ QUnit.test(
     logIn();
     Discourse.reset();
 
-    visit("/groups/discourse");
+    await visit("/groups/discourse");
 
-    click(".nav-pills li a[title='Messages']");
+    await click(".nav-pills li a[title='Messages']");
 
-    andThen(() => {
-      assert.equal(
-        find(".alert")
-          .text()
-          .trim(),
-        I18n.t("choose_topic.none_found"),
-        "it should display the right alert"
-      );
-    });
+    assert.equal(
+      find(".alert")
+        .text()
+        .trim(),
+      I18n.t("choose_topic.none_found"),
+      "it should display the right alert"
+    );
   }
 );
 
-QUnit.test("Admin viewing group messages", assert => {
+QUnit.test("Admin viewing group messages", async assert => {
   // prettier-ignore
   server.get("/topics/private-messages-group/eviltrout/discourse.json", () => { // eslint-disable-line no-undef
     return response({
@@ -252,41 +240,37 @@ QUnit.test("Admin viewing group messages", assert => {
   logIn();
   Discourse.reset();
 
-  visit("/groups/discourse");
-  click(".nav-pills li a[title='Messages']");
+  await visit("/groups/discourse");
+  await click(".nav-pills li a[title='Messages']");
 
-  andThen(() => {
-    assert.equal(
-      find(".topic-list-item .link-top-line")
-        .text()
-        .trim(),
-      "This is a private message 1",
-      "it should display the list of group topics"
-    );
-  });
+  assert.equal(
+    find(".topic-list-item .link-top-line")
+      .text()
+      .trim(),
+    "This is a private message 1",
+    "it should display the list of group topics"
+  );
 });
 
-QUnit.test("Admin Viewing Group", assert => {
+QUnit.test("Admin Viewing Group", async assert => {
   logIn();
   Discourse.reset();
 
-  visit("/groups/discourse");
+  await visit("/groups/discourse");
 
-  andThen(() => {
-    assert.ok(
-      find(".nav-pills li a[title='Manage']").length === 1,
-      "it should show manage group tab if user is admin"
-    );
+  assert.ok(
+    find(".nav-pills li a[title='Manage']").length === 1,
+    "it should show manage group tab if user is admin"
+  );
 
-    assert.equal(
-      count(".group-message-button"),
-      1,
-      "it displays show group message button"
-    );
-    assert.equal(
-      find(".group-info-name").text(),
-      "Awesome Team",
-      "it should display the group name"
-    );
-  });
+  assert.equal(
+    count(".group-message-button"),
+    1,
+    "it displays show group message button"
+  );
+  assert.equal(
+    find(".group-info-name").text(),
+    "Awesome Team",
+    "it should display the group name"
+  );
 });
diff --git a/test/javascripts/acceptance/login-with-email-and-hide-email-address-taken-test.js.es6 b/test/javascripts/acceptance/login-with-email-and-hide-email-address-taken-test.js.es6
index faa51b87400..a205a12d055 100644
--- a/test/javascripts/acceptance/login-with-email-and-hide-email-address-taken-test.js.es6
+++ b/test/javascripts/acceptance/login-with-email-and-hide-email-address-taken-test.js.es6
@@ -17,21 +17,19 @@ acceptance("Login with email - hide email address taken", {
   }
 });
 
-QUnit.test("with hide_email_address_taken enabled", assert => {
-  visit("/");
-  click("header .login-button");
-  fillIn("#login-account-name", "someuser@example.com");
-  click(".login-with-email-button");
+QUnit.test("with hide_email_address_taken enabled", async assert => {
+  await visit("/");
+  await click("header .login-button");
+  await fillIn("#login-account-name", "someuser@example.com");
+  await click(".login-with-email-button");
 
-  andThen(() => {
-    assert.equal(
-      find(".alert-success")
-        .html()
-        .trim(),
-      I18n.t("email_login.complete_email_found", {
-        email: "someuser@example.com"
-      }),
-      "it should display the success message for any email address"
-    );
-  });
+  assert.equal(
+    find(".alert-success")
+      .html()
+      .trim(),
+    I18n.t("email_login.complete_email_found", {
+      email: "someuser@example.com"
+    }),
+    "it should display the success message for any email address"
+  );
 });
diff --git a/test/javascripts/acceptance/login-with-email-and-no-social-logins-test.js.es6 b/test/javascripts/acceptance/login-with-email-and-no-social-logins-test.js.es6
index 7fc715a6c8a..a8b638de460 100644
--- a/test/javascripts/acceptance/login-with-email-and-no-social-logins-test.js.es6
+++ b/test/javascripts/acceptance/login-with-email-and-no-social-logins-test.js.es6
@@ -4,32 +4,21 @@ acceptance("Login with email - no social logins", {
   settings: {
     enable_local_logins_via_email: true
   },
-  beforeEach() {
-    const response = object => {
-      return [200, { "Content-Type": "application/json" }, object];
-    };
-
-    // prettier-ignore
-    server.post("/u/email-login", () => { // eslint-disable-line no-undef
-      return response({ success: "OK" });
-    });
+  pretend(server, helper) {
+    server.post("/u/email-login", () => helper.response({ success: "OK" }));
   }
 });
 
-QUnit.test("with login with email enabled", assert => {
-  visit("/");
-  click("header .login-button");
+QUnit.test("with login with email enabled", async assert => {
+  await visit("/");
+  await click("header .login-button");
 
-  andThen(() => {
-    assert.ok(exists(".login-with-email-button"));
-  });
+  assert.ok(exists(".login-with-email-button"));
 });
 
-QUnit.test("with login with email disabled", assert => {
-  visit("/");
-  click("header .login-button");
+QUnit.test("with login with email disabled", async assert => {
+  await visit("/");
+  await click("header .login-button");
 
-  andThen(() => {
-    assert.notOk(find(".login-buttons").is(":visible"));
-  });
+  assert.notOk(find(".login-buttons").is(":visible"));
 });
diff --git a/test/javascripts/acceptance/login-with-email-test.js.es6 b/test/javascripts/acceptance/login-with-email-test.js.es6
index 3d56fea32eb..738c2920d3e 100644
--- a/test/javascripts/acceptance/login-with-email-test.js.es6
+++ b/test/javascripts/acceptance/login-with-email-test.js.es6
@@ -7,96 +7,77 @@ acceptance("Login with email", {
     enable_local_logins_via_email: true,
     enable_facebook_logins: true
   },
-  beforeEach() {
-    const response = object => {
-      return [200, { "Content-Type": "application/json" }, object];
-    };
-
-    // prettier-ignore
-    server.post("/u/email-login", () => { // eslint-disable-line no-undef
-      return response({ success: "OK", user_found: userFound });
-    });
+  pretend(server, helper) {
+    server.post("/u/email-login", () =>
+      helper.response({ success: "OK", user_found: userFound })
+    );
   }
 });
 
-QUnit.test("with email button", assert => {
-  visit("/");
-  click("header .login-button");
+QUnit.test("with email button", async assert => {
+  await visit("/");
+  await click("header .login-button");
 
-  andThen(() => {
-    assert.ok(
-      exists(".btn-social.facebook"),
-      "it displays the facebook login button"
-    );
+  assert.ok(
+    exists(".btn-social.facebook"),
+    "it displays the facebook login button"
+  );
 
-    assert.ok(
-      exists(".login-with-email-button"),
-      "it displays the login with email button"
-    );
-  });
+  assert.ok(
+    exists(".login-with-email-button"),
+    "it displays the login with email button"
+  );
 
-  fillIn("#login-account-name", "someuser");
-  click(".login-with-email-button");
+  await fillIn("#login-account-name", "someuser");
+  await click(".login-with-email-button");
 
-  andThen(() => {
-    assert.equal(
-      find(".alert-error").html(),
-      I18n.t("email_login.complete_username_not_found", {
-        username: "someuser"
-      }),
-      "it should display an error for an invalid username"
-    );
-  });
+  assert.equal(
+    find(".alert-error").html(),
+    I18n.t("email_login.complete_username_not_found", {
+      username: "someuser"
+    }),
+    "it should display an error for an invalid username"
+  );
 
-  fillIn("#login-account-name", "someuser@gmail.com");
-  click(".login-with-email-button");
+  await fillIn("#login-account-name", "someuser@gmail.com");
+  await click(".login-with-email-button");
 
-  andThen(() => {
-    assert.equal(
-      find(".alert-error").html(),
-      I18n.t("email_login.complete_email_not_found", {
-        email: "someuser@gmail.com"
-      }),
-      "it should display an error for an invalid email"
-    );
-  });
+  assert.equal(
+    find(".alert-error").html(),
+    I18n.t("email_login.complete_email_not_found", {
+      email: "someuser@gmail.com"
+    }),
+    "it should display an error for an invalid email"
+  );
 
-  fillIn("#login-account-name", "someuser");
+  await fillIn("#login-account-name", "someuser");
 
-  andThen(() => {
-    userFound = true;
-  });
+  userFound = true;
 
-  click(".login-with-email-button");
+  await click(".login-with-email-button");
 
-  andThen(() => {
-    assert.equal(
-      find(".alert-success")
-        .html()
-        .trim(),
-      I18n.t("email_login.complete_username_found", { username: "someuser" }),
-      "it should display a success message for a valid username"
-    );
-  });
+  assert.equal(
+    find(".alert-success")
+      .html()
+      .trim(),
+    I18n.t("email_login.complete_username_found", { username: "someuser" }),
+    "it should display a success message for a valid username"
+  );
 
-  visit("/");
-  click("header .login-button");
-  fillIn("#login-account-name", "someuser@gmail.com");
-  click(".login-with-email-button");
+  await visit("/");
+  await click("header .login-button");
+  await fillIn("#login-account-name", "someuser@gmail.com");
+  await click(".login-with-email-button");
 
-  andThen(() => {
-    assert.equal(
-      find(".alert-success")
-        .html()
-        .trim(),
-      I18n.t("email_login.complete_email_found", {
-        email: "someuser@gmail.com"
-      }),
-      "it should display a success message for a valid email"
-    );
-  });
+  assert.equal(
+    find(".alert-success")
+      .html()
+      .trim(),
+    I18n.t("email_login.complete_email_found", {
+      email: "someuser@gmail.com"
+    }),
+    "it should display a success message for a valid email"
+  );
 
-  andThen(() => {
-    userFound = false;
-  });
+  userFound = false;
 });
diff --git a/test/javascripts/acceptance/password-reset-test.js.es6 b/test/javascripts/acceptance/password-reset-test.js.es6
index cb6ebb5c240..476c426f9fc 100644
--- a/test/javascripts/acceptance/password-reset-test.js.es6
+++ b/test/javascripts/acceptance/password-reset-test.js.es6
@@ -3,52 +3,47 @@ import PreloadStore from "preload-store";
 import { parsePostData } from "helpers/create-pretender";
 
 acceptance("Password Reset", {
-  beforeEach() {
-    const response = object => {
-      return [200, { "Content-Type": "application/json" }, object];
-    };
+  pretend(server, helper) {
+    server.get("/u/confirm-email-token/myvalidtoken.json", () =>
+      helper.response(200, { success: "OK" })
+    );
 
-    // prettier-ignore
-    server.get("/u/confirm-email-token/myvalidtoken.json", () => { //eslint-disable-line
-      return response({ success: "OK" });
-    });
+    server.get("/u/confirm-email-token/requiretwofactor.json", () =>
+      helper.response(200, { success: "OK" })
+    );
 
-    // prettier-ignore
-    server.put("/u/password-reset/myvalidtoken.json", request => { //eslint-disable-line
+    server.put("/u/password-reset/myvalidtoken.json", request => {
       const body = parsePostData(request.requestBody);
       if (body.password === "jonesyAlienSlayer") {
-        return response({
+        return helper.response(200, {
           success: false,
           errors: { password: ["is the name of your cat"] }
         });
       } else {
-        return response({
+        return helper.response(200, {
           success: "OK",
           message: I18n.t("password_reset.success")
         });
       }
     });
 
-    // prettier-ignore
-    server.get("/u/confirm-email-token/requiretwofactor.json", () => { //eslint-disable-line
-      return response({ success: "OK" });
-    });
-
-    // prettier-ignore
-    server.put("/u/password-reset/requiretwofactor.json", request => { //eslint-disable-line
+    server.put("/u/password-reset/requiretwofactor.json", request => {
       const body = parsePostData(request.requestBody);
       if (
         body.password === "perf3ctly5ecur3" &&
         body.second_factor_token === "123123"
       ) {
-        return response({
+        return helper.response(200, {
           success: "OK",
           message: I18n.t("password_reset.success")
         });
       } else if (body.second_factor_token === "123123") {
-        return response({ success: false, errors: { password: ["invalid"] } });
+        return helper.response(200, {
+          success: false,
+          errors: { password: ["invalid"] }
+        });
       } else {
-        return response({
+        return helper.response(200, {
           success: false,
           message: "invalid token",
           errors: { user_second_factors: ["invalid token"] }
@@ -58,88 +53,70 @@ acceptance("Password Reset", {
   }
 });
 
-QUnit.test("Password Reset Page", assert => {
+QUnit.test("Password Reset Page", async assert => {
   PreloadStore.store("password_reset", { is_developer: false });
 
-  visit("/u/password-reset/myvalidtoken");
-  andThen(() => {
-    assert.ok(exists(".password-reset input"), "shows the input");
-  });
+  await visit("/u/password-reset/myvalidtoken");
+  assert.ok(exists(".password-reset input"), "shows the input");
 
-  fillIn(".password-reset input", "perf3ctly5ecur3");
-  andThen(() => {
-    assert.ok(exists(".password-reset .tip.good"), "input looks good");
-  });
+  await fillIn(".password-reset input", "perf3ctly5ecur3");
+  assert.ok(exists(".password-reset .tip.good"), "input looks good");
 
-  fillIn(".password-reset input", "123");
-  andThen(() => {
-    assert.ok(exists(".password-reset .tip.bad"), "input is not valid");
-    assert.ok(
-      find(".password-reset .tip.bad")
-        .html()
-        .indexOf(I18n.t("user.password.too_short")) > -1,
-      "password too short"
-    );
-  });
+  await fillIn(".password-reset input", "123");
+  assert.ok(exists(".password-reset .tip.bad"), "input is not valid");
+  assert.ok(
+    find(".password-reset .tip.bad")
+      .html()
+      .indexOf(I18n.t("user.password.too_short")) > -1,
+    "password too short"
+  );
 
-  fillIn(".password-reset input", "jonesyAlienSlayer");
-  click(".password-reset form button");
-  andThen(() => {
-    assert.ok(exists(".password-reset .tip.bad"), "input is not valid");
-    assert.ok(
-      find(".password-reset .tip.bad")
-        .html()
-        .indexOf("is the name of your cat") > -1,
-      "server validation error message shows"
-    );
-  });
+  await fillIn(".password-reset input", "jonesyAlienSlayer");
+  await click(".password-reset form button");
+  assert.ok(exists(".password-reset .tip.bad"), "input is not valid");
+  assert.ok(
+    find(".password-reset .tip.bad")
+      .html()
+      .indexOf("is the name of your cat") > -1,
+    "server validation error message shows"
+  );
 
-  fillIn(".password-reset input", "perf3ctly5ecur3");
-  click(".password-reset form button");
-  andThen(() => {
-    assert.ok(!exists(".password-reset form"), "form is gone");
-  });
+  await fillIn(".password-reset input", "perf3ctly5ecur3");
+  await click(".password-reset form button");
+  assert.ok(!exists(".password-reset form"), "form is gone");
 });
 
-QUnit.test("Password Reset Page With Second Factor", assert => {
+QUnit.test("Password Reset Page With Second Factor", async assert => {
   PreloadStore.store("password_reset", {
     is_developer: false,
     second_factor_required: true
   });
 
-  visit("/u/password-reset/requiretwofactor");
+  await visit("/u/password-reset/requiretwofactor");
 
-  andThen(() => {
-    assert.notOk(exists("#new-account-password"), "does not show the input");
-    assert.ok(exists("#second-factor"), "shows the second factor prompt");
-  });
+  assert.notOk(exists("#new-account-password"), "does not show the input");
+  assert.ok(exists("#second-factor"), "shows the second factor prompt");
 
-  fillIn("input#second-factor", "0000");
-  click(".password-reset form button");
+  await fillIn("input#second-factor", "0000");
+  await click(".password-reset form button");
 
-  andThen(() => {
-    assert.ok(exists(".alert-error"), "shows 2 factor error");
+  assert.ok(exists(".alert-error"), "shows 2 factor error");
 
-    assert.ok(
-      find(".alert-error")
-        .html()
-        .indexOf("invalid token") > -1,
-      "shows server validation error message"
-    );
-  });
+  assert.ok(
+    find(".alert-error")
+      .html()
+      .indexOf("invalid token") > -1,
+    "shows server validation error message"
+  );
 
-  fillIn("input#second-factor", "123123");
-  click(".password-reset form button");
+  await fillIn("input#second-factor", "123123");
+  await click(".password-reset form button");
 
-  andThen(() => {
-    assert.notOk(exists(".alert-error"), "hides error");
-    assert.ok(exists("#new-account-password"), "shows the input");
-  });
+  assert.notOk(exists(".alert-error"), "hides error");
+  assert.ok(exists("#new-account-password"), "shows the input");
 
-  fillIn(".password-reset input", "perf3ctly5ecur3");
-  click(".password-reset form button");
+  await fillIn(".password-reset input", "perf3ctly5ecur3");
+  await click(".password-reset form button");
 
-  andThen(() => {
-    assert.ok(!exists(".password-reset form"), "form is gone");
-  });
+  assert.ok(!exists(".password-reset form"), "form is gone");
 });
diff --git a/test/javascripts/acceptance/preferences-test.js.es6 b/test/javascripts/acceptance/preferences-test.js.es6
index dff59326aa4..00df87be367 100644
--- a/test/javascripts/acceptance/preferences-test.js.es6
+++ b/test/javascripts/acceptance/preferences-test.js.es6
@@ -166,13 +166,11 @@ QUnit.test("second factor backup", async assert => {
   assert.ok(exists(".backup-codes-area"), "shows backup codes");
 });
 
-QUnit.test("default avatar selector", assert => {
-  visit("/u/eviltrout/preferences");
+QUnit.test("default avatar selector", async assert => {
+  await visit("/u/eviltrout/preferences");
 
-  click(".pref-avatar .btn");
-  andThen(() => {
-    assert.ok(exists(".avatar-choice", "opens the avatar selection modal"));
-  });
+  await click(".pref-avatar .btn");
+  assert.ok(exists(".avatar-choice", "opens the avatar selection modal"));
 });
 
 acceptance("Avatar selector when selectable avatars is enabled", {
@@ -202,15 +200,13 @@ acceptance("User Preferences when badges are disabled", {
   settings: { enable_badges: false }
 });
 
-QUnit.test("visit my preferences", assert => {
-  visit("/u/eviltrout/preferences");
-  andThen(() => {
-    assert.ok($("body.user-preferences-page").length, "has the body class");
-    assert.equal(
-      currentURL(),
-      "/u/eviltrout/preferences/account",
-      "defaults to account tab"
-    );
-    assert.ok(exists(".user-preferences"), "it shows the preferences");
-  });
+QUnit.test("visit my preferences", async assert => {
+  await visit("/u/eviltrout/preferences");
+  assert.ok($("body.user-preferences-page").length, "has the body class");
+  assert.equal(
+    currentURL(),
+    "/u/eviltrout/preferences/account",
+    "defaults to account tab"
+  );
+  assert.ok(exists(".user-preferences"), "it shows the preferences");
 });
diff --git a/test/javascripts/acceptance/queued-posts-test.js.es6 b/test/javascripts/acceptance/queued-posts-test.js.es6
index 2e62d365eda..561c821eb1c 100644
--- a/test/javascripts/acceptance/queued-posts-test.js.es6
+++ b/test/javascripts/acceptance/queued-posts-test.js.es6
@@ -2,99 +2,93 @@ import { acceptance } from "helpers/qunit-helpers";
 
 acceptance("Queued Posts", {
   loggedIn: true,
-  settings: { tagging_enabled: true }
+  settings: { tagging_enabled: true },
+  pretend(server, helper) {
+    server.get("/queued_posts", () => {
+      return helper.response({
+        users: [
+          {
+            id: 3,
+            username: "test_user",
+            avatar_template:
+              "/letter_avatar_proxy/v2/letter/t/eada6e/{size}.png",
+            active: true,
+            admin: false,
+            moderator: false,
+            last_seen_at: "2017-08-11T20:48:05.405Z",
+            last_emailed_at: null,
+            created_at: "2017-08-07T02:23:33.309Z",
+            last_seen_age: "1d",
+            last_emailed_age: null,
+            created_at_age: "6d",
+            username_lower: "test_user",
+            trust_level: 0,
+            trust_level_locked: false,
+            flag_level: 0,
+            title: null,
+            suspended_at: null,
+            suspended_till: null,
+            suspended: null,
+            silenced: false,
+            time_read: "19m",
+            staged: false,
+            days_visited: 4,
+            posts_read_count: 12,
+            topics_entered: 6,
+            post_count: 2
+          }
+        ],
+        queued_posts: [
+          {
+            id: 22,
+            queue: "default",
+            user_id: 3,
+            state: 1,
+            topic_id: null,
+            approved_by_id: null,
+            rejected_by_id: null,
+            raw: "some content",
+            post_options: {
+              archetype: "regular",
+              category: "1",
+              typing_duration_msecs: "3200",
+              composer_open_duration_msecs: "19007",
+              visible: true,
+              is_warning: false,
+              title: "a new topic that needs to be reviewed",
+              ip_address: "172.17.0.1",
+              first_post_checks: true,
+              is_poll: true
+            },
+            created_at: "2017-08-11T20:43:41.115Z",
+            category_id: 1,
+            can_delete_user: true
+          }
+        ],
+        __rest_serializer: "1",
+        refresh_queued_posts: "/queued_posts?status=new"
+      });
+    });
+  }
 });
 
 QUnit.test(
-  "For topics: body of post, title, category and tags are all editbale",
-  assert => {
-    // prettier-ignore
-    server.get("/queued_posts", () => { //eslint-disable-line no-undef
-      return [
-        200,
-        { "Content-Type": "application/json" },
-        {
-          users: [
-            {
-              id: 3,
-              username: "test_user",
-              avatar_template:
-                "/letter_avatar_proxy/v2/letter/t/eada6e/{size}.png",
-              active: true,
-              admin: false,
-              moderator: false,
-              last_seen_at: "2017-08-11T20:48:05.405Z",
-              last_emailed_at: null,
-              created_at: "2017-08-07T02:23:33.309Z",
-              last_seen_age: "1d",
-              last_emailed_age: null,
-              created_at_age: "6d",
-              username_lower: "test_user",
-              trust_level: 0,
-              trust_level_locked: false,
-              flag_level: 0,
-              title: null,
-              suspended_at: null,
-              suspended_till: null,
-              suspended: null,
-              silenced: false,
-              time_read: "19m",
-              staged: false,
-              days_visited: 4,
-              posts_read_count: 12,
-              topics_entered: 6,
-              post_count: 2
-            }
-          ],
-          queued_posts: [
-            {
-              id: 22,
-              queue: "default",
-              user_id: 3,
-              state: 1,
-              topic_id: null,
-              approved_by_id: null,
-              rejected_by_id: null,
-              raw: "some content",
-              post_options: {
-                archetype: "regular",
-                category: "1",
-                typing_duration_msecs: "3200",
-                composer_open_duration_msecs: "19007",
-                visible: true,
-                is_warning: false,
-                title: "a new topic that needs to be reviewed",
-                ip_address: "172.17.0.1",
-                first_post_checks: true,
-                is_poll: true
-              },
-              created_at: "2017-08-11T20:43:41.115Z",
-              category_id: 1,
-              can_delete_user: true
-            }
-          ],
-          __rest_serializer: "1",
-          refresh_queued_posts: "/queued_posts?status=new"
-        }
-      ];
-    });
+  "For topics: body of post, title, category and tags are all editable",
+  async assert => {
+    await visit("/queued-posts");
+    await click(".queued-posts .queued-post button.edit");
 
-    visit("/queued-posts");
-    click(".queued-posts .queued-post button.edit");
-
-    andThen(() => {
-      assert.ok(exists(".d-editor-container"), "the body should be editable");
-      assert.ok(
-        exists(".edit-title .ember-text-field"),
-        "the title should be editable"
-      );
-      assert.ok(exists(".category-chooser"), "category should be editbale");
-      assert.ok(exists(".tag-chooser"), "tags should be editable");
-    });
+    assert.ok(exists(".d-editor-container"), "the body should be editable");
+    assert.ok(
+      exists(".edit-title .ember-text-field"),
+      "the title should be editable"
+    );
+    assert.ok(exists(".category-chooser"), "category should be editable");
+    assert.ok(exists(".tag-chooser"), "tags should be editable");
   }
 );
 
-QUnit.test("For replies: only the body of post is editbale", assert => {
+QUnit.test("For replies: only the body of post is editable", async assert => {
   // prettier-ignore
   server.get("/queued_posts", () => { //eslint-disable-line no-undef
     return [
@@ -176,19 +170,14 @@ QUnit.test("For replies: only the body of post is editbale", assert => {
     ];
   });
 
-  visit("/queued-posts");
-  click(".queued-posts .queued-post button.edit");
+  await visit("/queued-posts");
+  await click(".queued-posts .queued-post button.edit");
 
-  andThen(() => {
-    assert.ok(exists(".d-editor-container"), "the body should be editable");
-    assert.notOk(
-      exists(".edit-title .ember-text-field"),
-      "title should not be editbale"
-    );
-    assert.notOk(
-      exists(".category-chooser"),
-      "category should not be editable"
-    );
-    assert.notOk(exists("div.tag-chooser"), "tags should not be editable");
-  });
+  assert.ok(exists(".d-editor-container"), "the body should be editable");
+  assert.notOk(
+    exists(".edit-title .ember-text-field"),
+    "title should not be editbale"
+  );
+  assert.notOk(exists(".category-chooser"), "category should not be editable");
+  assert.notOk(exists("div.tag-chooser"), "tags should not be editable");
 });
diff --git a/test/javascripts/acceptance/search-full-test.js.es6 b/test/javascripts/acceptance/search-full-test.js.es6
index aa767917109..a09f2c6cc24 100644
--- a/test/javascripts/acceptance/search-full-test.js.es6
+++ b/test/javascripts/acceptance/search-full-test.js.es6
@@ -2,19 +2,13 @@ import { acceptance, waitFor } from "helpers/qunit-helpers";
 acceptance("Search - Full Page", {
   settings: { tagging_enabled: true },
   loggedIn: true,
-  beforeEach() {
-    const response = object => {
-      return [200, { "Content-Type": "application/json" }, object];
-    };
-
-    // prettier-ignore
-    server.get("/tags/filter/search", () => { //eslint-disable-line
-      return response({ results: [{ text: "monkey", count: 1 }] });
+  pretend(server, helper) {
+    server.get("/tags/filter/search", () => {
+      return helper.response({ results: [{ text: "monkey", count: 1 }] });
     });
 
-    // prettier-ignore
-    server.get("/u/search/users", () => { //eslint-disable-line
-      return response({
+    server.get("/u/search/users", () => {
+      return helper.response({
         users: [
           {
             username: "admin",
@@ -25,36 +19,32 @@ acceptance("Search - Full Page", {
       });
     });
 
-    // prettier-ignore
-    server.get("/admin/groups.json", () => { //eslint-disable-line
-      return response([
-        {
-          id: 2,
-          automatic: true,
-          name: "moderators",
-          user_count: 4,
-          alias_level: 0,
-          visible: true,
-          automatic_membership_email_domains: null,
-          automatic_membership_retroactive: false,
-          primary_group: false,
-          title: null,
-          grant_trust_level: null,
-          incoming_email: null,
-          notification_level: null,
-          has_messages: true,
-          is_member: true,
-          mentionable: false,
-          flair_url: null,
-          flair_bg_color: null,
-          flair_color: null
-        }
-      ]);
+    server.get("/admin/groups.json", () => {
+      return helper.response({
+        id: 2,
+        automatic: true,
+        name: "moderators",
+        user_count: 4,
+        alias_level: 0,
+        visible: true,
+        automatic_membership_email_domains: null,
+        automatic_membership_retroactive: false,
+        primary_group: false,
+        title: null,
+        grant_trust_level: null,
+        incoming_email: null,
+        notification_level: null,
+        has_messages: true,
+        is_member: true,
+        mentionable: false,
+        flair_url: null,
+        flair_bg_color: null,
+        flair_color: null
+      });
     });
 
-    // prettier-ignore
-    server.get("/badges.json", () => { //eslint-disable-line
-      return response({
+    server.get("/badges.json", () => {
+      return helper.response({
         badge_types: [{ id: 3, name: "Bronze", sort_order: 7 }],
         badge_groupings: [
           {
@@ -92,105 +82,93 @@ acceptance("Search - Full Page", {
   }
 });
 
-QUnit.test("perform various searches", assert => {
-  visit("/search");
+QUnit.test("perform various searches", async assert => {
+  await visit("/search");
 
-  andThen(() => {
-    assert.ok($("body.search-page").length, "has body class");
-    assert.ok(exists(".search-container"), "has container class");
-    assert.ok(find(".search-query").length > 0);
-    assert.ok(find(".fps-topic").length === 0);
-  });
+  assert.ok($("body.search-page").length, "has body class");
+  assert.ok(exists(".search-container"), "has container class");
+  assert.ok(find(".search-query").length > 0);
+  assert.ok(find(".fps-topic").length === 0);
 
-  fillIn(".search-query", "none");
-  click(".search-cta");
+  await fillIn(".search-query", "none");
+  await click(".search-cta");
 
-  andThen(() => {
-    assert.ok(find(".fps-topic").length === 0, "has no results");
-    assert.ok(find(".no-results-suggestion .google-search-form"));
-  });
+  assert.ok(find(".fps-topic").length === 0, "has no results");
+  assert.ok(find(".no-results-suggestion .google-search-form"));
 
-  fillIn(".search-query", "posts");
-  click(".search-cta");
+  await fillIn(".search-query", "posts");
+  await click(".search-cta");
 
-  andThen(() => assert.ok(find(".fps-topic").length === 1, "has one post"));
+  assert.ok(find(".fps-topic").length === 1, "has one post");
 });
 
-QUnit.test("escape search term", assert => {
-  visit("/search");
-  fillIn(".search-query", "@<script>prompt(1337)</script>gmail.com");
+QUnit.test("escape search term", async assert => {
+  await visit("/search");
+  await fillIn(".search-query", "@<script>prompt(1337)</script>gmail.com");
 
-  andThen(() => {
+  assert.ok(
+    exists(
+      '.search-advanced-options span:contains("<script>prompt(1337)</script>gmail.com")'
+    ),
+    "it escapes search term"
+  );
+});
+
+QUnit.test("update username through advanced search ui", async assert => {
+  await visit("/search");
+  await fillIn(".search-query", "none");
+  await fillIn(".search-advanced-options .user-selector", "admin");
+  await click(".search-advanced-options .user-selector");
+  await keyEvent(".search-advanced-options .user-selector", "keydown", 8);
+
+  waitFor(assert, async () => {
+    assert.ok(
+      visible(".search-advanced-options .autocomplete"),
+      '"autocomplete" popup is visible'
+    );
     assert.ok(
       exists(
-        '.search-advanced-options span:contains("<script>prompt(1337)</script>gmail.com")'
+        '.search-advanced-options .autocomplete ul li a span.username:contains("admin")'
       ),
-      "it escapes search term"
+      '"autocomplete" popup has an entry for "admin"'
+    );
+
+    await click(".search-advanced-options .autocomplete ul li a:first");
+
+    assert.ok(
+      exists('.search-advanced-options span:contains("admin")'),
+      'has "admin" pre-populated'
+    );
+    assert.equal(
+      find(".search-query").val(),
+      "none @admin",
+      'has updated search term to "none user:admin"'
     );
   });
 });
 
-QUnit.test("update username through advanced search ui", assert => {
-  visit("/search");
-  fillIn(".search-query", "none");
-  fillIn(".search-advanced-options .user-selector", "admin");
-  click(".search-advanced-options .user-selector");
-  keyEvent(".search-advanced-options .user-selector", "keydown", 8);
-
-  andThen(() => {
-    waitFor(assert, () => {
-      assert.ok(
-        visible(".search-advanced-options .autocomplete"),
-        '"autocomplete" popup is visible'
-      );
-      assert.ok(
-        exists(
-          '.search-advanced-options .autocomplete ul li a span.username:contains("admin")'
-        ),
-        '"autocomplete" popup has an entry for "admin"'
-      );
-
-      click(".search-advanced-options .autocomplete ul li a:first");
-
-      andThen(() => {
-        assert.ok(
-          exists('.search-advanced-options span:contains("admin")'),
-          'has "admin" pre-populated'
-        );
-        assert.equal(
-          find(".search-query").val(),
-          "none @admin",
-          'has updated search term to "none user:admin"'
-        );
-      });
-    });
-  });
-});
-
-QUnit.test("update category through advanced search ui", assert => {
+QUnit.test("update category through advanced search ui", async assert => {
   const categoryChooser = selectKit(
     ".search-advanced-options .category-chooser"
   );
 
-  visit("/search");
+  await visit("/search");
 
-  fillIn(".search-query", "none");
-  categoryChooser
-    .expand()
-    .fillInFilter("faq")
-    .selectRowByValue(4);
+  await fillIn(".search-query", "none");
 
-  andThen(() => {
-    assert.ok(
-      exists('.search-advanced-options .badge-category:contains("faq")'),
-      'has "faq" populated'
-    );
-    assert.equal(
-      find(".search-query").val(),
-      "none #faq",
-      'has updated search term to "none #faq"'
-    );
-  });
+  await categoryChooser.expandAwait();
+  await categoryChooser.fillInFilter("faq");
+  await categoryChooser.selectRowByValueAwait(4);
+
+  assert.ok(
+    exists('.search-advanced-options .badge-category:contains("faq")'),
+    'has "faq" populated'
+  );
+  assert.equal(
+    find(".search-query").val(),
+    "none #faq",
+    'has updated search term to "none #faq"'
+  );
 });
 
 // test("update group through advanced search ui", assert => {
@@ -297,12 +275,13 @@ QUnit.test(
   }
 );
 
-QUnit.test("update in:private filter through advanced search ui", assert => {
-  visit("/search");
-  fillIn(".search-query", "none");
-  click(".search-advanced-options .in-private");
+QUnit.test(
+  "update in:private filter through advanced search ui",
+  async assert => {
+    await visit("/search");
+    await fillIn(".search-query", "none");
+    await click(".search-advanced-options .in-private");
 
-  andThen(() => {
     assert.ok(
       exists(".search-advanced-options .in-private:checked"),
       'has "are in my messages" populated'
@@ -312,128 +291,119 @@ QUnit.test("update in:private filter through advanced search ui", assert => {
       "none in:private",
       'has updated search term to "none in:private"'
     );
-  });
+  }
+);
+
+QUnit.test("update in:seen filter through advanced search ui", async assert => {
+  await visit("/search");
+  await fillIn(".search-query", "none");
+  await click(".search-advanced-options .in-seen");
+
+  assert.ok(
+    exists(".search-advanced-options .in-seen:checked"),
+    "it should check the right checkbox"
+  );
+
+  assert.equal(
+    find(".search-query").val(),
+    "none in:seen",
+    "it should update the search term"
+  );
 });
 
-QUnit.test("update in:seen filter through advanced search ui", assert => {
-  visit("/search");
-  fillIn(".search-query", "none");
-  click(".search-advanced-options .in-seen");
-
-  andThen(() => {
-    assert.ok(
-      exists(".search-advanced-options .in-seen:checked"),
-      "it should check the right checkbox"
-    );
-
-    assert.equal(
-      find(".search-query").val(),
-      "none in:seen",
-      "it should update the search term"
-    );
-  });
-});
-
-QUnit.test("update in filter through advanced search ui", assert => {
+QUnit.test("update in filter through advanced search ui", async assert => {
   const inSelector = selectKit(".search-advanced-options .select-kit#in");
 
-  visit("/search");
+  await visit("/search");
 
-  fillIn(".search-query", "none");
-  inSelector.expand().selectRowByValue("bookmarks");
+  await fillIn(".search-query", "none");
+  await inSelector.expandAwait();
+  await inSelector.selectRowByValueAwait("bookmarks");
 
-  andThen(() => {
-    assert.ok(
-      inSelector.rowByName("I bookmarked").exists(),
-      'has "I bookmarked" populated'
-    );
-    assert.equal(
-      find(".search-query").val(),
-      "none in:bookmarks",
-      'has updated search term to "none in:bookmarks"'
-    );
-  });
+  assert.ok(
+    inSelector.rowByName("I bookmarked").exists(),
+    'has "I bookmarked" populated'
+  );
+  assert.equal(
+    find(".search-query").val(),
+    "none in:bookmarks",
+    'has updated search term to "none in:bookmarks"'
+  );
 });
 
-QUnit.test("update status through advanced search ui", assert => {
+QUnit.test("update status through advanced search ui", async assert => {
   const statusSelector = selectKit(
     ".search-advanced-options .select-kit#status"
   );
 
-  visit("/search");
+  await visit("/search");
 
-  fillIn(".search-query", "none");
-  statusSelector.expand().selectRowByValue("closed");
+  await fillIn(".search-query", "none");
+  await statusSelector.expandAwait();
+  await statusSelector.selectRowByValueAwait("closed");
 
-  andThen(() => {
-    assert.ok(
-      statusSelector.rowByName("are closed").exists(),
-      'has "are closed" populated'
-    );
-    assert.equal(
-      find(".search-query").val(),
-      "none status:closed",
-      'has updated search term to "none status:closed"'
-    );
-  });
+  assert.ok(
+    statusSelector.rowByName("are closed").exists(),
+    'has "are closed" populated'
+  );
+  assert.equal(
+    find(".search-query").val(),
+    "none status:closed",
+    'has updated search term to "none status:closed"'
+  );
 });
 
-QUnit.test("update post time through advanced search ui", assert => {
+QUnit.test("update post time through advanced search ui", async assert => {
   const postTimeSelector = selectKit(
     ".search-advanced-options .select-kit#postTime"
   );
 
-  visit("/search");
+  await visit("/search");
 
-  fillIn(".search-query", "none");
-  fillIn("#search-post-date .date-picker", "2016-10-05");
-  postTimeSelector.expand().selectRowByValue("after");
+  await fillIn(".search-query", "none");
+  await fillIn("#search-post-date .date-picker", "2016-10-05");
+  await postTimeSelector.expandAwait();
+  await postTimeSelector.selectRowByValueAwait("after");
 
-  andThen(() => {
-    assert.ok(
-      postTimeSelector.rowByName("after").exists(),
-      'has "after" populated'
-    );
-    assert.equal(
-      find(".search-query").val(),
-      "none after:2016-10-05",
-      'has updated search term to "none after:2016-10-05"'
-    );
-  });
+  assert.ok(
+    postTimeSelector.rowByName("after").exists(),
+    'has "after" populated'
+  );
+  assert.equal(
+    find(".search-query").val(),
+    "none after:2016-10-05",
+    'has updated search term to "none after:2016-10-05"'
+  );
 });
 
-QUnit.test("update min post count through advanced search ui", assert => {
-  visit("/search");
-  fillIn(".search-query", "none");
-  fillIn("#search-min-post-count", "5");
+QUnit.test("update min post count through advanced search ui", async assert => {
+  await visit("/search");
+  await fillIn(".search-query", "none");
+  await fillIn("#search-min-post-count", "5");
 
-  andThen(() => {
-    assert.equal(
-      find(".search-advanced-options #search-min-post-count").val(),
-      "5",
-      'has "5" populated'
-    );
-    assert.equal(
-      find(".search-query").val(),
-      "none min_post_count:5",
-      'has updated search term to "none min_post_count:5"'
-    );
-  });
+  assert.equal(
+    find(".search-advanced-options #search-min-post-count").val(),
+    "5",
+    'has "5" populated'
+  );
+  assert.equal(
+    find(".search-query").val(),
+    "none min_post_count:5",
+    'has updated search term to "none min_post_count:5"'
+  );
 });
 
-QUnit.test("validate advanced search when initially empty", assert => {
-  visit("/search?expanded=true");
-  click(".search-advanced-options .in-likes");
+QUnit.test("validate advanced search when initially empty", async assert => {
+  await visit("/search?expanded=true");
+  await click(".search-advanced-options .in-likes");
 
-  andThen(() => {
-    assert.ok(
-      exists(".search-advanced-options .in-likes:checked"),
-      'has "I liked" populated'
-    );
-    assert.equal(
-      find(".search-query").val(),
-      "in:likes",
-      'has updated search term to "in:likes"'
-    );
-  });
+  assert.ok(
+    exists(".search-advanced-options .in-likes:checked"),
+    'has "I liked" populated'
+  );
+  assert.equal(
+    find(".search-query").val(),
+    "in:likes",
+    'has updated search term to "in:likes"'
+  );
 });
diff --git a/test/javascripts/acceptance/tag-hashtag-test.js.es6 b/test/javascripts/acceptance/tag-hashtag-test.js.es6
index 11182aec80f..29b0b40085a 100644
--- a/test/javascripts/acceptance/tag-hashtag-test.js.es6
+++ b/test/javascripts/acceptance/tag-hashtag-test.js.es6
@@ -3,50 +3,37 @@ import { acceptance } from "helpers/qunit-helpers";
 acceptance("Tag Hashtag", {
   loggedIn: true,
   settings: { tagging_enabled: true },
-  beforeEach() {
-    const response = object => {
-      return [200, { "Content-Type": "application/json" }, object];
-    };
-
-    // prettier-ignore
-    server.get("/tags/filter/search", () => { //eslint-disable-line
-      return response({ results: [{ text: "monkey", count: 1 }] });
+  pretend(server, helper) {
+    server.get("/tags/filter/search", () => {
+      return helper.response({ results: [{ text: "monkey", count: 1 }] });
     });
 
-    // prettier-ignore
-    server.get("/category_hashtags/check", () => { //eslint-disable-line
-      return response({ valid: [] });
-    });
-
-    // prettier-ignore
-    server.get("/tags/check", () => { //eslint-disable-line
-      return response({ valid: [{ value: "monkey", url: "/tags/monkey" }] });
+    server.get("/tags/check", () => {
+      return helper.response({
+        valid: [{ value: "monkey", url: "/tags/monkey" }]
+      });
     });
   }
 });
 
-QUnit.test("tag is cooked properly", assert => {
-  visit("/t/internationalization-localization/280");
-  click("#topic-footer-buttons .btn.create");
+QUnit.test("tag is cooked properly", async assert => {
+  await visit("/t/internationalization-localization/280");
+  await click("#topic-footer-buttons .btn.create");
 
-  fillIn(".d-editor-input", "this is a tag hashtag #monkey::tag");
-  andThen(() => {
-    // TODO: Test that the autocomplete shows
-    assert.equal(
-      find(".d-editor-preview:visible")
-        .html()
-        .trim(),
-      '<p>this is a tag hashtag <a href="/tags/monkey" class="hashtag">#<span>monkey</span></a></p>'
-    );
-  });
+  await fillIn(".d-editor-input", "this is a tag hashtag #monkey::tag");
+  // TODO: Test that the autocomplete shows
+  assert.equal(
+    find(".d-editor-preview:visible")
+      .html()
+      .trim(),
+    '<p>this is a tag hashtag <a href="/tags/monkey" class="hashtag">#<span>monkey</span></a></p>'
+  );
 
-  click("#reply-control .btn.create");
-  andThen(() => {
-    assert.equal(
-      find(".topic-post:last .cooked")
-        .html()
-        .trim(),
-      '<p>this is a tag hashtag <a href="/tags/monkey" class="hashtag">#<span>monkey</span></a></p>'
-    );
-  });
+  await click("#reply-control .btn.create");
+  assert.equal(
+    find(".topic-post:last .cooked")
+      .html()
+      .trim(),
+    '<p>this is a tag hashtag <a href="/tags/monkey" class="hashtag">#<span>monkey</span></a></p>'
+  );
 });
diff --git a/test/javascripts/acceptance/tags-test.js.es6 b/test/javascripts/acceptance/tags-test.js.es6
index 5052ebd0b33..5b4e1d0c0a5 100644
--- a/test/javascripts/acceptance/tags-test.js.es6
+++ b/test/javascripts/acceptance/tags-test.js.es6
@@ -1,13 +1,11 @@
 import { acceptance } from "helpers/qunit-helpers";
 acceptance("Tags", { loggedIn: true });
 
-QUnit.test("list the tags", assert => {
-  visit("/tags");
+QUnit.test("list the tags", async assert => {
+  await visit("/tags");
 
-  andThen(() => {
-    assert.ok($("body.tags-page").length, "has the body class");
-    assert.ok(exists(".tag-eviltrout"), "shows the evil trout tag");
-  });
+  assert.ok($("body.tags-page").length, "has the body class");
+  assert.ok(exists(".tag-eviltrout"), "shows the evil trout tag");
 });
 
 acceptance("Tags listed by group", {
@@ -17,7 +15,7 @@ acceptance("Tags listed by group", {
   }
 });
 
-QUnit.test("list the tags in groups", assert => {
+QUnit.test("list the tags in groups", async assert => {
   // prettier-ignore
   server.get("/tags", () => { // eslint-disable-line no-undef
     return [
@@ -57,30 +55,28 @@ QUnit.test("list the tags in groups", assert => {
     ];
   });
 
-  visit("/tags");
-  andThen(() => {
-    assert.equal(
-      $(".tag-list").length,
-      4,
-      "shows separate lists for the 3 groups and the ungrouped tags"
-    );
-    assert.ok(
-      _.isEqual(
-        _.map($(".tag-list h3"), i => {
-          return $(i).text();
-        }),
-        ["Ford Cars", "Honda Cars", "Makes", "Other Tags"]
-      ),
-      "shown in given order and with tags that are not in a group"
-    );
-    assert.ok(
-      _.isEqual(
-        _.map($(".tag-list:first .discourse-tag"), i => {
-          return $(i).text();
-        }),
-        ["focus", "escort"]
-      ),
-      "shows the tags in default sort (by count)"
-    );
-  });
+  await visit("/tags");
+  assert.equal(
+    $(".tag-list").length,
+    4,
+    "shows separate lists for the 3 groups and the ungrouped tags"
+  );
+  assert.ok(
+    _.isEqual(
+      _.map($(".tag-list h3"), i => {
+        return $(i).text();
+      }),
+      ["Ford Cars", "Honda Cars", "Makes", "Other Tags"]
+    ),
+    "shown in given order and with tags that are not in a group"
+  );
+  assert.ok(
+    _.isEqual(
+      _.map($(".tag-list:first .discourse-tag"), i => {
+        return $(i).text();
+      }),
+      ["focus", "escort"]
+    ),
+    "shows the tags in default sort (by count)"
+  );
 });
diff --git a/test/javascripts/acceptance/topic-edit-timer-test.js.es6 b/test/javascripts/acceptance/topic-edit-timer-test.js.es6
index 99851739e40..3d969ba8c90 100644
--- a/test/javascripts/acceptance/topic-edit-timer-test.js.es6
+++ b/test/javascripts/acceptance/topic-edit-timer-test.js.es6
@@ -1,271 +1,9 @@
 import { acceptance, replaceCurrentUser } from "helpers/qunit-helpers";
-acceptance("Topic - Edit timer", { loggedIn: true });
-
-const response = object => [
-  200,
-  { "Content-Type": "application/json" },
-  object
-];
-
-QUnit.test("default", assert => {
-  const timerType = selectKit(".select-kit.timer-type");
-  const futureDateInputSelector = selectKit(".future-date-input-selector");
-
-  visit("/t/internationalization-localization");
-  click(".toggle-admin-menu");
-  click(".topic-admin-status-update button");
-
-  andThen(() => {
-    assert.equal(
-      futureDateInputSelector.header().title(),
-      "Select a timeframe"
-    );
-    assert.equal(futureDateInputSelector.header().value(), null);
-  });
-
-  click("#private-topic-timer");
-
-  andThen(() => {
-    assert.equal(timerType.header().title(), "Remind Me");
-    assert.equal(timerType.header().value(), "reminder");
-
-    assert.equal(
-      futureDateInputSelector.header().title(),
-      "Select a timeframe"
-    );
-    assert.equal(futureDateInputSelector.header().value(), null);
-  });
-});
-
-QUnit.test("autoclose - specific time", assert => {
-  const futureDateInputSelector = selectKit(".future-date-input-selector");
-
-  visit("/t/internationalization-localization");
-  click(".toggle-admin-menu");
-  click(".topic-admin-status-update button");
-
-  futureDateInputSelector.expand().selectRowByValue("next_week");
-
-  andThen(() => {
-    assert.equal(futureDateInputSelector.header().title(), "Next week");
-    assert.equal(futureDateInputSelector.header().value(), "next_week");
-
-    const regex = /will automatically close in/g;
-    const html = find(".future-date-input .topic-status-info")
-      .html()
-      .trim();
-    assert.ok(regex.test(html));
-  });
-});
-
-QUnit.test("autoclose", assert => {
-  const futureDateInputSelector = selectKit(".future-date-input-selector");
-
-  visit("/t/internationalization-localization");
-  click(".toggle-admin-menu");
-  click(".topic-admin-status-update button");
-
-  futureDateInputSelector.expand().selectRowByValue("next_week");
-
-  andThen(() => {
-    assert.equal(futureDateInputSelector.header().title(), "Next week");
-    assert.equal(futureDateInputSelector.header().value(), "next_week");
-
-    const regex = /will automatically close in/g;
-    const html = find(".future-date-input .topic-status-info")
-      .html()
-      .trim();
-    assert.ok(regex.test(html));
-  });
-
-  futureDateInputSelector.expand().selectRowByValue("pick_date_and_time");
-
-  fillIn(".future-date-input .date-picker", "2099-11-24");
-
-  andThen(() => {
-    assert.equal(
-      futureDateInputSelector.header().title(),
-      "Pick date and time"
-    );
-    assert.equal(
-      futureDateInputSelector.header().value(),
-      "pick_date_and_time"
-    );
-
-    const regex = /will automatically close in/g;
-    const html = find(".future-date-input .topic-status-info")
-      .html()
-      .trim();
-    assert.ok(regex.test(html));
-  });
-
-  futureDateInputSelector.expand().selectRowByValue("set_based_on_last_post");
-
-  fillIn(".future-date-input input[type=number]", "2");
-
-  andThen(() => {
-    assert.equal(
-      futureDateInputSelector.header().title(),
-      "Close based on last post"
-    );
-    assert.equal(
-      futureDateInputSelector.header().value(),
-      "set_based_on_last_post"
-    );
-
-    const regex = /This topic will close.*after the last reply/g;
-    const html = find(".future-date-input .topic-status-info")
-      .html()
-      .trim();
-    assert.ok(regex.test(html));
-  });
-});
-
-QUnit.test("close temporarily", assert => {
-  const timerType = selectKit(".select-kit.timer-type");
-  const futureDateInputSelector = selectKit(".future-date-input-selector");
-
-  visit("/t/internationalization-localization");
-  click(".toggle-admin-menu");
-  click(".topic-admin-status-update button");
-
-  timerType.expand().selectRowByValue("open");
-
-  andThen(() => {
-    assert.equal(
-      futureDateInputSelector.header().title(),
-      "Select a timeframe"
-    );
-    assert.equal(futureDateInputSelector.header().value(), null);
-  });
-
-  futureDateInputSelector.expand().selectRowByValue("next_week");
-
-  andThen(() => {
-    assert.equal(futureDateInputSelector.header().title(), "Next week");
-    assert.equal(futureDateInputSelector.header().value(), "next_week");
-
-    const regex = /will automatically open in/g;
-    const html = find(".future-date-input .topic-status-info")
-      .html()
-      .trim();
-    assert.ok(regex.test(html));
-  });
-
-  futureDateInputSelector.expand().selectRowByValue("pick_date_and_time");
-
-  fillIn(".future-date-input .date-picker", "2099-11-24");
-
-  andThen(() => {
-    assert.equal(
-      futureDateInputSelector.header().title(),
-      "Pick date and time"
-    );
-    assert.equal(
-      futureDateInputSelector.header().value(),
-      "pick_date_and_time"
-    );
-
-    const regex = /will automatically open in/g;
-    const html = find(".future-date-input .topic-status-info")
-      .html()
-      .trim();
-    assert.ok(regex.test(html));
-  });
-});
-
-QUnit.test("schedule", assert => {
-  const timerType = selectKit(".select-kit.timer-type");
-  const categoryChooser = selectKit(".modal-body .category-chooser");
-  const futureDateInputSelector = selectKit(".future-date-input-selector");
-
-  visit("/t/internationalization-localization");
-  click(".toggle-admin-menu");
-  click(".topic-admin-status-update button");
-
-  timerType.expand().selectRowByValue("publish_to_category");
-
-  andThen(() => {
-    assert.equal(categoryChooser.header().title(), "uncategorized");
-    assert.equal(categoryChooser.header().value(), null);
-
-    assert.equal(
-      futureDateInputSelector.header().title(),
-      "Select a timeframe"
-    );
-    assert.equal(futureDateInputSelector.header().value(), null);
-  });
-
-  categoryChooser.expand().selectRowByValue("7");
-
-  futureDateInputSelector.expand().selectRowByValue("next_week");
-
-  andThen(() => {
-    assert.equal(futureDateInputSelector.header().title(), "Next week");
-    assert.equal(futureDateInputSelector.header().value(), "next_week");
-
-    const regex = /will be published to #dev/g;
-    const text = find(".future-date-input .topic-status-info")
-      .text()
-      .trim();
-    assert.ok(regex.test(text));
-  });
-});
-
-QUnit.test("TL4 can't auto-delete", assert => {
-  replaceCurrentUser({ staff: false, trust_level: 4 });
-
-  visit("/t/internationalization-localization");
-  click(".toggle-admin-menu");
-  click(".topic-admin-status-update button");
-
-  const timerType = selectKit(".select-kit.timer-type");
-
-  timerType.expand();
-
-  andThen(() => {
-    assert.ok(!timerType.rowByValue("delete").exists());
-  });
-});
-
-QUnit.test("auto delete", assert => {
-  const timerType = selectKit(".select-kit.timer-type");
-  const futureDateInputSelector = selectKit(".future-date-input-selector");
-
-  visit("/t/internationalization-localization");
-  click(".toggle-admin-menu");
-  click(".topic-admin-status-update button");
-
-  timerType.expand().selectRowByValue("delete");
-
-  andThen(() => {
-    assert.equal(
-      futureDateInputSelector.header().title(),
-      "Select a timeframe"
-    );
-    assert.equal(futureDateInputSelector.header().value(), null);
-  });
-
-  futureDateInputSelector.expand().selectRowByValue("two_weeks");
-
-  andThen(() => {
-    assert.equal(futureDateInputSelector.header().title(), "Two Weeks");
-    assert.equal(futureDateInputSelector.header().value(), "two_weeks");
-
-    const regex = /will be automatically deleted/g;
-    const html = find(".future-date-input .topic-status-info")
-      .html()
-      .trim();
-    assert.ok(regex.test(html));
-  });
-});
-
-QUnit.test(
-  "Manually closing before the timer will clear the status text",
-  async assert => {
-    // prettier-ignore
-    server.post("/t/280/timer", () => // eslint-disable-line no-undef
-      response({
+acceptance("Topic - Edit timer", {
+  loggedIn: true,
+  pretend(server, helper) {
+    server.post("/t/280/timer", () =>
+      helper.response({
         success: "OK",
         execute_at: new Date(
           new Date().getTime() + 1 * 60 * 60 * 1000
@@ -277,14 +15,228 @@ QUnit.test(
       })
     );
 
-    // prettier-ignore
-    server.put("/t/internationalization-localization/280/status", () => // eslint-disable-line no-undef
-      response({
+    server.put("/t/internationalization-localization/280/status", () =>
+      helper.response({
         success: "OK",
         topic_status_update: null
       })
     );
+  }
+});
 
+QUnit.test("default", async assert => {
+  const timerType = selectKit(".select-kit.timer-type");
+  const futureDateInputSelector = selectKit(".future-date-input-selector");
+
+  await visit("/t/internationalization-localization");
+  await click(".toggle-admin-menu");
+  await click(".topic-admin-status-update button");
+
+  assert.equal(futureDateInputSelector.header().title(), "Select a timeframe");
+  assert.equal(futureDateInputSelector.header().value(), null);
+
+  await click("#private-topic-timer");
+
+  assert.equal(timerType.header().title(), "Remind Me");
+  assert.equal(timerType.header().value(), "reminder");
+
+  assert.equal(futureDateInputSelector.header().title(), "Select a timeframe");
+  assert.equal(futureDateInputSelector.header().value(), null);
+});
+
+QUnit.test("autoclose - specific time", async assert => {
+  const futureDateInputSelector = selectKit(".future-date-input-selector");
+
+  await visit("/t/internationalization-localization");
+  await click(".toggle-admin-menu");
+  await click(".topic-admin-status-update button");
+
+  await futureDateInputSelector.expandAwait();
+  await futureDateInputSelector.selectRowByValueAwait("next_week");
+
+  assert.equal(futureDateInputSelector.header().title(), "Next week");
+  assert.equal(futureDateInputSelector.header().value(), "next_week");
+
+  const regex = /will automatically close in/g;
+  const html = find(".future-date-input .topic-status-info")
+    .html()
+    .trim();
+  assert.ok(regex.test(html));
+});
+
+QUnit.test("autoclose", async assert => {
+  const futureDateInputSelector = selectKit(".future-date-input-selector");
+
+  await visit("/t/internationalization-localization");
+  await click(".toggle-admin-menu");
+  await click(".topic-admin-status-update button");
+
+  await futureDateInputSelector.expandAwait();
+  await futureDateInputSelector.selectRowByValueAwait("next_week");
+
+  assert.equal(futureDateInputSelector.header().title(), "Next week");
+  assert.equal(futureDateInputSelector.header().value(), "next_week");
+
+  const regex1 = /will automatically close in/g;
+  const html1 = find(".future-date-input .topic-status-info")
+    .html()
+    .trim();
+  assert.ok(regex1.test(html1));
+
+  await futureDateInputSelector.expandAwait();
+  await futureDateInputSelector.selectRowByValueAwait("pick_date_and_time");
+
+  await fillIn(".future-date-input .date-picker", "2099-11-24");
+
+  assert.equal(futureDateInputSelector.header().title(), "Pick date and time");
+  assert.equal(futureDateInputSelector.header().value(), "pick_date_and_time");
+
+  const regex2 = /will automatically close in/g;
+  const html2 = find(".future-date-input .topic-status-info")
+    .html()
+    .trim();
+  assert.ok(regex2.test(html2));
+
+  await futureDateInputSelector.expandAwait();
+  await futureDateInputSelector.selectRowByValueAwait("set_based_on_last_post");
+
+  await fillIn(".future-date-input input[type=number]", "2");
+
+  assert.equal(
+    futureDateInputSelector.header().title(),
+    "Close based on last post"
+  );
+  assert.equal(
+    futureDateInputSelector.header().value(),
+    "set_based_on_last_post"
+  );
+
+  const regex3 = /This topic will close.*after the last reply/g;
+  const html3 = find(".future-date-input .topic-status-info")
+    .html()
+    .trim();
+  assert.ok(regex3.test(html3));
+});
+
+QUnit.test("close temporarily", async assert => {
+  const timerType = selectKit(".select-kit.timer-type");
+  const futureDateInputSelector = selectKit(".future-date-input-selector");
+
+  await visit("/t/internationalization-localization");
+  await click(".toggle-admin-menu");
+  await click(".topic-admin-status-update button");
+
+  await timerType.expandAwait();
+  await timerType.selectRowByValueAwait("open");
+
+  assert.equal(futureDateInputSelector.header().title(), "Select a timeframe");
+  assert.equal(futureDateInputSelector.header().value(), null);
+
+  await futureDateInputSelector.expandAwait();
+  await futureDateInputSelector.selectRowByValueAwait("next_week");
+
+  assert.equal(futureDateInputSelector.header().title(), "Next week");
+  assert.equal(futureDateInputSelector.header().value(), "next_week");
+
+  const regex1 = /will automatically open in/g;
+  const html1 = find(".future-date-input .topic-status-info")
+    .html()
+    .trim();
+  assert.ok(regex1.test(html1));
+
+  await futureDateInputSelector.expandAwait();
+  await futureDateInputSelector.selectRowByValueAwait("pick_date_and_time");
+
+  await fillIn(".future-date-input .date-picker", "2099-11-24");
+
+  assert.equal(futureDateInputSelector.header().title(), "Pick date and time");
+  assert.equal(futureDateInputSelector.header().value(), "pick_date_and_time");
+
+  const regex2 = /will automatically open in/g;
+  const html2 = find(".future-date-input .topic-status-info")
+    .html()
+    .trim();
+  assert.ok(regex2.test(html2));
+});
+
+QUnit.test("schedule", async assert => {
+  const timerType = selectKit(".select-kit.timer-type");
+  const categoryChooser = selectKit(".modal-body .category-chooser");
+  const futureDateInputSelector = selectKit(".future-date-input-selector");
+
+  await visit("/t/internationalization-localization");
+  await click(".toggle-admin-menu");
+  await click(".topic-admin-status-update button");
+
+  await timerType.expandAwait();
+  await timerType.selectRowByValueAwait("publish_to_category");
+
+  assert.equal(categoryChooser.header().title(), "uncategorized");
+  assert.equal(categoryChooser.header().value(), null);
+
+  assert.equal(futureDateInputSelector.header().title(), "Select a timeframe");
+  assert.equal(futureDateInputSelector.header().value(), null);
+
+  await categoryChooser.expandAwait();
+  await categoryChooser.selectRowByValueAwait("7");
+
+  await futureDateInputSelector.expandAwait();
+  await futureDateInputSelector.selectRowByValueAwait("next_week");
+
+  assert.equal(futureDateInputSelector.header().title(), "Next week");
+  assert.equal(futureDateInputSelector.header().value(), "next_week");
+
+  const regex = /will be published to #dev/g;
+  const text = find(".future-date-input .topic-status-info")
+    .text()
+    .trim();
+  assert.ok(regex.test(text));
+});
+
+QUnit.test("TL4 can't auto-delete", async assert => {
+  replaceCurrentUser({ staff: false, trust_level: 4 });
+
+  await visit("/t/internationalization-localization");
+  await click(".toggle-admin-menu");
+  await click(".topic-admin-status-update button");
+
+  const timerType = selectKit(".select-kit.timer-type");
+
+  await timerType.expandAwait();
+
+  assert.ok(!timerType.rowByValue("delete").exists());
+});
+
+QUnit.test("auto delete", async assert => {
+  const timerType = selectKit(".select-kit.timer-type");
+  const futureDateInputSelector = selectKit(".future-date-input-selector");
+
+  await visit("/t/internationalization-localization");
+  await click(".toggle-admin-menu");
+  await click(".topic-admin-status-update button");
+
+  await timerType.expandAwait();
+  await timerType.selectRowByValueAwait("delete");
+
+  assert.equal(futureDateInputSelector.header().title(), "Select a timeframe");
+  assert.equal(futureDateInputSelector.header().value(), null);
+
+  await futureDateInputSelector.expandAwait();
+  await futureDateInputSelector.selectRowByValueAwait("two_weeks");
+
+  assert.equal(futureDateInputSelector.header().title(), "Two Weeks");
+  assert.equal(futureDateInputSelector.header().value(), "two_weeks");
+
+  const regex = /will be automatically deleted/g;
+  const html = find(".future-date-input .topic-status-info")
+    .html()
+    .trim();
+  assert.ok(regex.test(html));
+});
+
+QUnit.test(
+  "Manually closing before the timer will clear the status text",
+  async assert => {
     const futureDateInputSelector = selectKit(".future-date-input-selector");
 
     await visit("/t/internationalization-localization");
diff --git a/test/javascripts/acceptance/topic-notifications-button-test.js.es6 b/test/javascripts/acceptance/topic-notifications-button-test.js.es6
index 7b38d694557..87d8f239fba 100644
--- a/test/javascripts/acceptance/topic-notifications-button-test.js.es6
+++ b/test/javascripts/acceptance/topic-notifications-button-test.js.es6
@@ -1,39 +1,31 @@
 import { acceptance } from "helpers/qunit-helpers";
 acceptance("Topic Notifications button", {
   loggedIn: true,
-  beforeEach() {
-    const response = object => {
-      return [200, { "Content-Type": "application/json" }, object];
-    };
-
-    // prettier-ignore
-    server.post("/t/280/notifications", () => { // eslint-disable-line no-undef
-      return response({});
+  pretend(server, helper) {
+    server.post("/t/280/notifications", () => {
+      return helper.response({});
     });
   }
 });
 
-QUnit.test("Updating topic notification level", assert => {
+QUnit.test("Updating topic notification level", async assert => {
   const notificationOptions = selectKit(
     "#topic-footer-buttons .topic-notifications-options"
   );
 
-  visit("/t/internationalization-localization/280");
+  await visit("/t/internationalization-localization/280");
 
-  andThen(() => {
-    assert.ok(
-      notificationOptions.exists(),
-      "it should display the notification options button in the topic's footer"
-    );
-  });
+  assert.ok(
+    notificationOptions.exists(),
+    "it should display the notification options button in the topic's footer"
+  );
 
-  notificationOptions.expand().selectRowByValue("3");
+  await notificationOptions.expandAwait();
+  await notificationOptions.selectRowByValueAwait("3");
 
-  andThen(() => {
-    assert.equal(
-      notificationOptions.selectedRow().name(),
-      "Watching",
-      "it should display the right notification level"
-    );
-  });
+  assert.equal(
+    notificationOptions.selectedRow().name(),
+    "Watching",
+    "it should display the right notification level"
+  );
 });
diff --git a/test/javascripts/acceptance/topic-test.js.es6 b/test/javascripts/acceptance/topic-test.js.es6
index 77710c79fcc..9f9473e60a2 100644
--- a/test/javascripts/acceptance/topic-test.js.es6
+++ b/test/javascripts/acceptance/topic-test.js.es6
@@ -1,21 +1,22 @@
 import { acceptance } from "helpers/qunit-helpers";
-acceptance("Topic", { loggedIn: true });
+acceptance("Topic", {
+  loggedIn: true,
+  pretend(server, helper) {
+    server.put("/posts/398/wiki", () => {
+      return helper.response({});
+    });
+  }
+});
 
-QUnit.test("Share Popup", assert => {
-  visit("/t/internationalization-localization/280");
-  andThen(() => {
-    assert.ok(!exists("#share-link.visible"), "it is not visible");
-  });
+QUnit.test("Share Popup", async assert => {
+  await visit("/t/internationalization-localization/280");
+  assert.ok(!exists("#share-link.visible"), "it is not visible");
 
-  click("button[data-share-url]");
-  andThen(() => {
-    assert.ok(exists("#share-link.visible"), "it shows the popup");
-  });
+  await click("button[data-share-url]");
+  assert.ok(exists("#share-link.visible"), "it shows the popup");
 
-  click("#share-link .close-share");
-  andThen(() => {
-    assert.ok(!exists("#share-link.visible"), "it closes the popup");
-  });
+  await click("#share-link .close-share");
+  assert.ok(!exists("#share-link.visible"), "it closes the popup");
 
   // TODO tgxworld This fails on Travis but we need to push the security fix out
   // first.
@@ -30,183 +31,159 @@ QUnit.test("Share Popup", assert => {
   // });
 });
 
-QUnit.test("Showing and hiding the edit controls", assert => {
-  visit("/t/internationalization-localization/280");
+QUnit.test("Showing and hiding the edit controls", async assert => {
+  await visit("/t/internationalization-localization/280");
 
-  click("#topic-title .d-icon-pencil");
+  await click("#topic-title .d-icon-pencil");
 
-  andThen(() => {
-    assert.ok(exists("#edit-title"), "it shows the editing controls");
-    assert.ok(
-      !exists(".title-wrapper .remove-featured-link"),
-      "link to remove featured link is not shown"
-    );
-  });
+  assert.ok(exists("#edit-title"), "it shows the editing controls");
+  assert.ok(
+    !exists(".title-wrapper .remove-featured-link"),
+    "link to remove featured link is not shown"
+  );
 
-  fillIn("#edit-title", "this is the new title");
-  click("#topic-title .cancel-edit");
-  andThen(() => {
-    assert.ok(!exists("#edit-title"), "it hides the editing controls");
-  });
+  await fillIn("#edit-title", "this is the new title");
+  await click("#topic-title .cancel-edit");
+  assert.ok(!exists("#edit-title"), "it hides the editing controls");
 });
 
-QUnit.test("Updating the topic title and category", assert => {
+QUnit.test("Updating the topic title and category", async assert => {
   const categoryChooser = selectKit(".title-wrapper .category-chooser");
 
-  visit("/t/internationalization-localization/280");
+  await visit("/t/internationalization-localization/280");
 
-  click("#topic-title .d-icon-pencil");
-  fillIn("#edit-title", "this is the new title");
-  categoryChooser.expand().selectRowByValue(4);
-  click("#topic-title .submit-edit");
+  await click("#topic-title .d-icon-pencil");
+  await fillIn("#edit-title", "this is the new title");
+  await categoryChooser.expandAwait();
+  await categoryChooser.selectRowByValueAwait(4);
+  await click("#topic-title .submit-edit");
 
-  andThen(() => {
-    assert.equal(
-      find("#topic-title .badge-category").text(),
-      "faq",
-      "it displays the new category"
-    );
-    assert.equal(
-      find(".fancy-title")
-        .text()
-        .trim(),
-      "this is the new title",
-      "it displays the new title"
-    );
-  });
+  assert.equal(
+    find("#topic-title .badge-category").text(),
+    "faq",
+    "it displays the new category"
+  );
+  assert.equal(
+    find(".fancy-title")
+      .text()
+      .trim(),
+    "this is the new title",
+    "it displays the new title"
+  );
 });
 
-QUnit.test("Marking a topic as wiki", assert => {
-  // prettier-ignore
-  server.put("/posts/398/wiki", () => { // eslint-disable-line no-undef
-    return [200, { "Content-Type": "application/json" }, {}];
-  });
+QUnit.test("Marking a topic as wiki", async assert => {
+  await visit("/t/internationalization-localization/280");
 
-  visit("/t/internationalization-localization/280");
+  assert.ok(find("a.wiki").length === 0, "it does not show the wiki icon");
 
-  andThen(() => {
-    assert.ok(find("a.wiki").length === 0, "it does not show the wiki icon");
-  });
+  await click(".topic-post:eq(0) button.show-more-actions");
+  await click(".topic-post:eq(0) button.show-post-admin-menu");
+  await click(".btn.wiki");
 
-  click(".topic-post:eq(0) button.show-more-actions");
-  click(".topic-post:eq(0) button.show-post-admin-menu");
-  click(".btn.wiki");
-
-  andThen(() => {
-    assert.ok(find("a.wiki").length === 1, "it shows the wiki icon");
-  });
+  assert.ok(find("a.wiki").length === 1, "it shows the wiki icon");
 });
 
-QUnit.test("Reply as new topic", assert => {
-  visit("/t/internationalization-localization/280");
-  click("button.share:eq(0)");
-  click(".reply-as-new-topic a");
+QUnit.test("Reply as new topic", async assert => {
+  await visit("/t/internationalization-localization/280");
+  await click("button.share:eq(0)");
+  await click(".reply-as-new-topic a");
 
-  andThen(() => {
-    assert.ok(exists(".d-editor-input"), "the composer input is visible");
+  assert.ok(exists(".d-editor-input"), "the composer input is visible");
 
-    assert.equal(
-      find(".d-editor-input")
-        .val()
-        .trim(),
-      `Continuing the discussion from [Internationalization / localization](${
-        window.location.origin
-      }/t/internationalization-localization/280):`,
-      "it fills composer with the ring string"
-    );
-    assert.equal(
-      selectKit(".category-chooser")
-        .header()
-        .value(),
-      "2",
-      "it fills category selector with the right category"
-    );
-  });
+  assert.equal(
+    find(".d-editor-input")
+      .val()
+      .trim(),
+    `Continuing the discussion from [Internationalization / localization](${
+      window.location.origin
+    }/t/internationalization-localization/280):`,
+    "it fills composer with the ring string"
+  );
+  assert.equal(
+    selectKit(".category-chooser")
+      .header()
+      .value(),
+    "2",
+    "it fills category selector with the right category"
+  );
 });
 
-QUnit.test("Reply as new message", assert => {
-  visit("/t/pm-for-testing/12");
-  click("button.share:eq(0)");
-  click(".reply-as-new-topic a");
+QUnit.test("Reply as new message", async assert => {
+  await visit("/t/pm-for-testing/12");
+  await click("button.share:eq(0)");
+  await click(".reply-as-new-topic a");
 
-  andThen(() => {
-    assert.ok(exists(".d-editor-input"), "the composer input is visible");
+  assert.ok(exists(".d-editor-input"), "the composer input is visible");
 
-    assert.equal(
-      find(".d-editor-input")
-        .val()
-        .trim(),
-      `Continuing the discussion from [PM for testing](${
-        window.location.origin
-      }/t/pm-for-testing/12):`,
-      "it fills composer with the ring string"
-    );
+  assert.equal(
+    find(".d-editor-input")
+      .val()
+      .trim(),
+    `Continuing the discussion from [PM for testing](${
+      window.location.origin
+    }/t/pm-for-testing/12):`,
+    "it fills composer with the ring string"
+  );
 
-    const targets = find(".item span", ".composer-fields");
+  const targets = find(".item span", ".composer-fields");
 
-    assert.equal(
-      $(targets[0]).text(),
-      "someguy",
-      "it fills up the composer with the right user to start the PM to"
-    );
+  assert.equal(
+    $(targets[0]).text(),
+    "someguy",
+    "it fills up the composer with the right user to start the PM to"
+  );
 
-    assert.equal(
-      $(targets[1]).text(),
-      "test",
-      "it fills up the composer with the right user to start the PM to"
-    );
+  assert.equal(
+    $(targets[1]).text(),
+    "test",
+    "it fills up the composer with the right user to start the PM to"
+  );
 
-    assert.equal(
-      $(targets[2]).text(),
-      "Group",
-      "it fills up the composer with the right group to start the PM to"
-    );
-  });
+  assert.equal(
+    $(targets[2]).text(),
+    "Group",
+    "it fills up the composer with the right group to start the PM to"
+  );
 });
 
-QUnit.test("Visit topic routes", assert => {
-  visit("/t/12");
+QUnit.test("Visit topic routes", async assert => {
+  await visit("/t/12");
 
-  andThen(() => {
-    assert.equal(
-      find(".fancy-title")
-        .text()
-        .trim(),
-      "PM for testing",
-      "it routes to the right topic"
-    );
-  });
+  assert.equal(
+    find(".fancy-title")
+      .text()
+      .trim(),
+    "PM for testing",
+    "it routes to the right topic"
+  );
 
-  visit("/t/280/20");
+  await visit("/t/280/20");
 
-  andThen(() => {
-    assert.equal(
-      find(".fancy-title")
-        .text()
-        .trim(),
-      "Internationalization / localization",
-      "it routes to the right topic"
-    );
-  });
+  assert.equal(
+    find(".fancy-title")
+      .text()
+      .trim(),
+    "Internationalization / localization",
+    "it routes to the right topic"
+  );
 });
 
-QUnit.test("Updating the topic title with emojis", assert => {
-  visit("/t/internationalization-localization/280");
-  click("#topic-title .d-icon-pencil");
+QUnit.test("Updating the topic title with emojis", async assert => {
+  await visit("/t/internationalization-localization/280");
+  await click("#topic-title .d-icon-pencil");
 
-  fillIn("#edit-title", "emojis title :bike: :blonde_woman:t6:");
+  await fillIn("#edit-title", "emojis title :bike: :blonde_woman:t6:");
 
-  click("#topic-title .submit-edit");
+  await click("#topic-title .submit-edit");
 
-  andThen(() => {
-    assert.equal(
-      find(".fancy-title")
-        .html()
-        .trim(),
-      'emojis title <img src="/images/emoji/emoji_one/bike.png?v=5" title="bike" alt="bike" class="emoji"> <img src="/images/emoji/emoji_one/blonde_woman/6.png?v=5" title="blonde_woman:t6" alt="blonde_woman:t6" class="emoji">',
-      "it displays the new title with emojis"
-    );
-  });
+  assert.equal(
+    find(".fancy-title")
+      .html()
+      .trim(),
+    'emojis title <img src="/images/emoji/emoji_one/bike.png?v=5" title="bike" alt="bike" class="emoji"> <img src="/images/emoji/emoji_one/blonde_woman/6.png?v=5" title="blonde_woman:t6" alt="blonde_woman:t6" class="emoji">',
+    "it displays the new title with emojis"
+  );
 });
 
 acceptance("Topic featured links", {
@@ -217,29 +194,23 @@ acceptance("Topic featured links", {
   }
 });
 
-QUnit.test("remove featured link", assert => {
-  visit("/t/299/1");
-  andThen(() => {
-    assert.ok(
-      exists(".title-wrapper .topic-featured-link"),
-      "link is shown with topic title"
-    );
-  });
+QUnit.test("remove featured link", async assert => {
+  await visit("/t/299/1");
+  assert.ok(
+    exists(".title-wrapper .topic-featured-link"),
+    "link is shown with topic title"
+  );
 
-  click(".title-wrapper .edit-topic");
-  andThen(() => {
-    assert.ok(
-      exists(".title-wrapper .remove-featured-link"),
-      "link to remove featured link"
-    );
-  });
+  await click(".title-wrapper .edit-topic");
+  assert.ok(
+    exists(".title-wrapper .remove-featured-link"),
+    "link to remove featured link"
+  );
 
   // this test only works in a browser:
-  // click('.title-wrapper .remove-featured-link');
-  // click('.title-wrapper .submit-edit');
-  // andThen(() => {
-  //   assert.ok(!exists('.title-wrapper .topic-featured-link'), 'link is gone');
-  // });
+  // await click('.title-wrapper .remove-featured-link');
+  // await click('.title-wrapper .submit-edit');
+  // assert.ok(!exists('.title-wrapper .topic-featured-link'), 'link is gone');
 });
 
 QUnit.test("selecting posts", async assert => {