FEATURE: user status emoji (#17025)
This commit is contained in:
parent
0b8e6adabe
commit
033f72c65f
|
@ -14,6 +14,7 @@ import { isEmpty } from "@ember/utils";
|
|||
import { prioritizeNameInUx } from "discourse/lib/settings";
|
||||
import { dasherize } from "@ember/string";
|
||||
import { emojiUnescape } from "discourse/lib/text";
|
||||
import { escapeExpression } from "discourse/lib/utilities";
|
||||
|
||||
export default Component.extend(CardContentsBase, CanCheckEmails, CleansUp, {
|
||||
elementId: "user-card",
|
||||
|
@ -55,10 +56,9 @@ export default Component.extend(CardContentsBase, CanCheckEmails, CleansUp, {
|
|||
return this.siteSettings.enable_user_status && this.user.status;
|
||||
},
|
||||
|
||||
@discourseComputed("user.status")
|
||||
userStatusEmoji() {
|
||||
const emoji = this.user.status.emoji ?? "mega";
|
||||
return emojiUnescape(`:${emoji}:`);
|
||||
@discourseComputed("user.status.emoji")
|
||||
userStatusEmoji(emoji) {
|
||||
return emojiUnescape(escapeExpression(`:${emoji}:`));
|
||||
},
|
||||
|
||||
isSuspendedOrHasBio: or("user.suspend_reason", "user.bio_excerpt"),
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
import Component from "@ember/component";
|
||||
import { action, computed } from "@ember/object";
|
||||
import { scheduleOnce } from "@ember/runloop";
|
||||
import { emojiUnescape } from "discourse/lib/text";
|
||||
import { escapeExpression } from "discourse/lib/utilities";
|
||||
|
||||
export default class UserStatusPicker extends Component {
|
||||
tagName = "";
|
||||
isFocused = false;
|
||||
emojiPickerIsActive = false;
|
||||
emoji = null;
|
||||
description = null;
|
||||
|
||||
@computed("emoji")
|
||||
get emojiHtml() {
|
||||
const emoji = escapeExpression(`:${this.emoji}:`);
|
||||
return emojiUnescape(emoji);
|
||||
}
|
||||
|
||||
@action
|
||||
blur() {
|
||||
this.set("isFocused", false);
|
||||
}
|
||||
|
||||
@action
|
||||
emojiSelected(emoji) {
|
||||
this.set("emoji", emoji);
|
||||
this.set("emojiPickerIsActive", false);
|
||||
|
||||
scheduleOnce("afterRender", () => {
|
||||
document.querySelector(".btn-emoji")?.focus();
|
||||
});
|
||||
}
|
||||
|
||||
@action
|
||||
focus() {
|
||||
this.set("isFocused", true);
|
||||
}
|
||||
|
||||
@action
|
||||
onEmojiPickerOutsideClick() {
|
||||
this.set("emojiPickerIsActive", false);
|
||||
}
|
||||
|
||||
@action
|
||||
setDefaultEmoji() {
|
||||
if (!this.emoji) {
|
||||
this.set("emoji", "speech_balloon");
|
||||
}
|
||||
}
|
||||
|
||||
@action
|
||||
toggleEmojiPicker(event) {
|
||||
event.stopPropagation();
|
||||
this.set("emojiPickerIsActive", !this.emojiPickerIsActive);
|
||||
}
|
||||
}
|
|
@ -1,49 +1,49 @@
|
|||
import Controller from "@ember/controller";
|
||||
import ModalFunctionality from "discourse/mixins/modal-functionality";
|
||||
import { action } from "@ember/object";
|
||||
import { notEmpty } from "@ember/object/computed";
|
||||
import { inject as service } from "@ember/service";
|
||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||
import bootbox from "bootbox";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
|
||||
export default Controller.extend(ModalFunctionality, {
|
||||
userStatusService: service("user-status"),
|
||||
|
||||
emoji: null,
|
||||
description: null,
|
||||
statusIsSet: notEmpty("description"),
|
||||
showDeleteButton: false,
|
||||
|
||||
onShow() {
|
||||
if (this.currentUser.status) {
|
||||
this.setProperties({
|
||||
description: this.currentUser.status.description,
|
||||
showDeleteButton: true,
|
||||
});
|
||||
}
|
||||
const status = this.currentUser.status;
|
||||
this.setProperties({
|
||||
emoji: status?.emoji,
|
||||
description: status?.description,
|
||||
showDeleteButton: !!status,
|
||||
});
|
||||
},
|
||||
|
||||
@discourseComputed("emoji", "description")
|
||||
statusIsSet(emoji, description) {
|
||||
return !!emoji && !!description;
|
||||
},
|
||||
|
||||
@action
|
||||
delete() {
|
||||
this.userStatusService
|
||||
.clear()
|
||||
.then(() => {
|
||||
this._resetModal();
|
||||
this.send("closeModal");
|
||||
})
|
||||
.then(() => this.send("closeModal"))
|
||||
.catch((e) => this._handleError(e));
|
||||
},
|
||||
|
||||
@action
|
||||
saveAndClose() {
|
||||
if (this.description) {
|
||||
const status = { description: this.description };
|
||||
this.userStatusService
|
||||
.set(status)
|
||||
.then(() => {
|
||||
this.send("closeModal");
|
||||
})
|
||||
.catch((e) => this._handleError(e));
|
||||
}
|
||||
const status = { description: this.description, emoji: this.emoji };
|
||||
this.userStatusService
|
||||
.set(status)
|
||||
.then(() => {
|
||||
this.send("closeModal");
|
||||
})
|
||||
.catch((e) => this._handleError(e));
|
||||
},
|
||||
|
||||
_handleError(e) {
|
||||
|
@ -53,9 +53,4 @@ export default Controller.extend(ModalFunctionality, {
|
|||
popupAjaxError(e);
|
||||
}
|
||||
},
|
||||
|
||||
_resetModal() {
|
||||
this.set("description", null);
|
||||
this.set("showDeleteButton", false);
|
||||
},
|
||||
});
|
||||
|
|
|
@ -8,7 +8,7 @@ export default class UserStatusService extends Service {
|
|||
await ajax({
|
||||
url: "/user-status.json",
|
||||
type: "PUT",
|
||||
data: { description: status.description },
|
||||
data: status,
|
||||
});
|
||||
|
||||
this.currentUser.set("status", status);
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
<div class="user-status-picker-wrap">
|
||||
<div class="emoji-picker-anchor user-status-picker {{if this.isFocused "focused"}}">
|
||||
<button
|
||||
type="button"
|
||||
class="btn-emoji btn-flat"
|
||||
onclick={{action "toggleEmojiPicker"}}
|
||||
{{on "focus" this.focus}}
|
||||
{{on "blur" this.blur}}
|
||||
>
|
||||
{{#if @emoji}}
|
||||
{{html-safe this.emojiHtml}}
|
||||
{{else}}
|
||||
{{d-icon "discourse-emojis"}}
|
||||
{{/if}}
|
||||
</button>
|
||||
<Input
|
||||
class="user-status-description"
|
||||
@value={{@description}}
|
||||
placeholder={{i18n "user_status.what_are_you_doing"}}
|
||||
{{on "input" this.setDefaultEmoji}}
|
||||
{{on "focus" this.focus}}
|
||||
{{on "blur" this.blur}} />
|
||||
</div>
|
||||
</div>
|
||||
{{emoji-picker
|
||||
isActive=this.emojiPickerIsActive
|
||||
emojiSelected=(action "emojiSelected")
|
||||
onEmojiPickerClose=(action "onEmojiPickerOutsideClick")
|
||||
placement="bottom"
|
||||
}}
|
|
@ -1,10 +1,7 @@
|
|||
{{#d-modal-body}}
|
||||
{{#conditional-loading-spinner condition=loading}}
|
||||
<div class="control-group user-status-description-wrap">
|
||||
{{input
|
||||
class="user-status-description"
|
||||
placeholder=(i18n "user_status.what_are_you_doing")
|
||||
value=description}}
|
||||
<div class="control-group">
|
||||
{{user-status-picker emoji=emoji description=description}}
|
||||
</div>
|
||||
<div class="modal-footer control-group">
|
||||
{{d-button
|
||||
|
|
|
@ -30,10 +30,9 @@ createWidgetFrom(QuickAccessItem, "user-status-item", {
|
|||
const action = "hideMenuAndSetStatus";
|
||||
const userStatus = this.currentUser.status;
|
||||
if (userStatus) {
|
||||
const emoji = userStatus.emoji ?? "mega";
|
||||
return this.attach("flat-button", {
|
||||
action,
|
||||
emoji,
|
||||
emoji: userStatus.emoji,
|
||||
translatedLabel: userStatus.description,
|
||||
});
|
||||
} else {
|
||||
|
|
|
@ -4,7 +4,6 @@ export default createWidget("user-status-bubble", {
|
|||
tagName: "div.user-status-background",
|
||||
|
||||
html(attrs) {
|
||||
const emoji = attrs.emoji ?? "mega";
|
||||
return this.attach("emoji", { name: emoji });
|
||||
return this.attach("emoji", { name: attrs.emoji });
|
||||
},
|
||||
});
|
||||
|
|
|
@ -8,9 +8,21 @@ import {
|
|||
import { click, fillIn, visit } from "@ember/test-helpers";
|
||||
import { test } from "qunit";
|
||||
|
||||
async function openUserStatusModal() {
|
||||
await click(".header-dropdown-toggle.current-user");
|
||||
await click(".menu-links-row .user-preferences-link");
|
||||
await click(".user-status button");
|
||||
}
|
||||
|
||||
async function pickEmoji(emoji) {
|
||||
await click(".btn-emoji");
|
||||
await fillIn(".emoji-picker-content .filter", emoji);
|
||||
await click(".results .emoji");
|
||||
}
|
||||
|
||||
acceptance("User Status", function (needs) {
|
||||
const userStatusFallbackEmoji = "mega";
|
||||
const userStatus = "off to dentist";
|
||||
const userStatusEmoji = "tooth";
|
||||
const userId = 1;
|
||||
|
||||
needs.user({ id: userId });
|
||||
|
@ -19,6 +31,7 @@ acceptance("User Status", function (needs) {
|
|||
server.put("/user-status.json", () => {
|
||||
publishToMessageBus(`/user-status/${userId}`, {
|
||||
description: userStatus,
|
||||
emoji: userStatusEmoji,
|
||||
});
|
||||
return helper.response({ success: true });
|
||||
});
|
||||
|
@ -38,7 +51,7 @@ acceptance("User Status", function (needs) {
|
|||
assert.notOk(exists("div.quick-access-panel li.user-status"));
|
||||
});
|
||||
|
||||
test("shows the user status button on the menu when disabled in settings", async function (assert) {
|
||||
test("shows the user status button on the menu when enabled in settings", async function (assert) {
|
||||
this.siteSettings.enable_user_status = true;
|
||||
|
||||
await visit("/");
|
||||
|
@ -57,7 +70,9 @@ acceptance("User Status", function (needs) {
|
|||
|
||||
test("shows user status on loaded page", async function (assert) {
|
||||
this.siteSettings.enable_user_status = true;
|
||||
updateCurrentUser({ status: { description: userStatus } });
|
||||
updateCurrentUser({
|
||||
status: { description: userStatus, emoji: userStatusEmoji },
|
||||
});
|
||||
|
||||
await visit("/");
|
||||
await click(".header-dropdown-toggle.current-user");
|
||||
|
@ -72,30 +87,75 @@ acceptance("User Status", function (needs) {
|
|||
|
||||
assert.equal(
|
||||
query("div.quick-access-panel li.user-status img.emoji").alt,
|
||||
`:${userStatusFallbackEmoji}:`,
|
||||
`:${userStatusEmoji}:`,
|
||||
"shows user status emoji on the menu"
|
||||
);
|
||||
|
||||
assert.equal(
|
||||
query(".header-dropdown-toggle .user-status-background img.emoji").alt,
|
||||
`:${userStatusFallbackEmoji}:`,
|
||||
`:${userStatusEmoji}:`,
|
||||
"shows user status emoji on the user avatar in the header"
|
||||
);
|
||||
});
|
||||
|
||||
test("shows user status on the user status modal", async function (assert) {
|
||||
this.siteSettings.enable_user_status = true;
|
||||
|
||||
updateCurrentUser({
|
||||
status: { description: userStatus, emoji: userStatusEmoji },
|
||||
});
|
||||
|
||||
await visit("/");
|
||||
await openUserStatusModal();
|
||||
|
||||
assert.equal(
|
||||
query(`.btn-emoji img.emoji`).title,
|
||||
userStatusEmoji,
|
||||
"status emoji is shown"
|
||||
);
|
||||
assert.equal(
|
||||
query(".user-status-description").value,
|
||||
userStatus,
|
||||
"status description is shown"
|
||||
);
|
||||
});
|
||||
|
||||
test("emoji picking", async function (assert) {
|
||||
this.siteSettings.enable_user_status = true;
|
||||
|
||||
await visit("/");
|
||||
await openUserStatusModal();
|
||||
|
||||
assert.ok(exists(`.d-icon-discourse-emojis`), "empty status icon is shown");
|
||||
|
||||
await click(".btn-emoji");
|
||||
assert.ok(exists(".emoji-picker.opened"), "emoji picker is opened");
|
||||
|
||||
await fillIn(".emoji-picker-content .filter", userStatusEmoji);
|
||||
await click(".results .emoji");
|
||||
assert.ok(
|
||||
exists(`.btn-emoji img.emoji[title=${userStatusEmoji}]`),
|
||||
"chosen status emoji is shown"
|
||||
);
|
||||
});
|
||||
|
||||
test("setting user status", async function (assert) {
|
||||
this.siteSettings.enable_user_status = true;
|
||||
|
||||
await visit("/");
|
||||
await click(".header-dropdown-toggle.current-user");
|
||||
await click(".menu-links-row .user-preferences-link");
|
||||
await click(".user-status button");
|
||||
await openUserStatusModal();
|
||||
|
||||
await fillIn(".user-status-description", userStatus);
|
||||
await click(".btn-primary");
|
||||
await pickEmoji(userStatusEmoji);
|
||||
assert.ok(
|
||||
exists(`.btn-emoji img.emoji[title=${userStatusEmoji}]`),
|
||||
"chosen status emoji is shown"
|
||||
);
|
||||
await click(".btn-primary"); // save
|
||||
|
||||
assert.equal(
|
||||
query(".header-dropdown-toggle .user-status-background img.emoji").alt,
|
||||
`:${userStatusFallbackEmoji}:`,
|
||||
`:${userStatusEmoji}:`,
|
||||
"shows user status emoji on the user avatar in the header"
|
||||
);
|
||||
|
||||
|
@ -110,7 +170,7 @@ acceptance("User Status", function (needs) {
|
|||
|
||||
assert.equal(
|
||||
query("div.quick-access-panel li.user-status img.emoji").alt,
|
||||
`:${userStatusFallbackEmoji}:`,
|
||||
`:${userStatusEmoji}:`,
|
||||
"shows user status emoji on the menu"
|
||||
);
|
||||
});
|
||||
|
@ -121,11 +181,11 @@ acceptance("User Status", function (needs) {
|
|||
const updatedStatus = "off to dentist the second time";
|
||||
|
||||
await visit("/");
|
||||
await click(".header-dropdown-toggle.current-user");
|
||||
await click(".menu-links-row .user-preferences-link");
|
||||
await click(".user-status button");
|
||||
await openUserStatusModal();
|
||||
|
||||
await fillIn(".user-status-description", updatedStatus);
|
||||
await click(".btn-primary");
|
||||
await pickEmoji(userStatusEmoji);
|
||||
await click(".btn-primary"); // save
|
||||
|
||||
await click(".header-dropdown-toggle.current-user");
|
||||
await click(".menu-links-row .user-preferences-link");
|
||||
|
@ -135,6 +195,11 @@ acceptance("User Status", function (needs) {
|
|||
updatedStatus,
|
||||
"shows user status description on the menu"
|
||||
);
|
||||
assert.equal(
|
||||
query("div.quick-access-panel li.user-status img.emoji").alt,
|
||||
`:${userStatusEmoji}:`,
|
||||
"shows user status emoji on the menu"
|
||||
);
|
||||
});
|
||||
|
||||
test("clearing user status", async function (assert) {
|
||||
|
@ -142,22 +207,68 @@ acceptance("User Status", function (needs) {
|
|||
updateCurrentUser({ status: { description: userStatus } });
|
||||
|
||||
await visit("/");
|
||||
await click(".header-dropdown-toggle.current-user");
|
||||
await click(".menu-links-row .user-preferences-link");
|
||||
await click(".user-status button");
|
||||
await openUserStatusModal();
|
||||
await click(".btn.delete-status");
|
||||
|
||||
assert.notOk(exists(".header-dropdown-toggle .user-status-background"));
|
||||
});
|
||||
|
||||
test("it's impossible to set status without description", async function (assert) {
|
||||
this.siteSettings.enable_user_status = true;
|
||||
|
||||
await visit("/");
|
||||
await openUserStatusModal();
|
||||
await pickEmoji(userStatusEmoji);
|
||||
|
||||
assert.ok(exists(`.btn-primary[disabled]`), "the save button is disabled");
|
||||
});
|
||||
|
||||
test("sets default status emoji automatically after user started inputting status description", async function (assert) {
|
||||
this.siteSettings.enable_user_status = true;
|
||||
const defaultStatusEmoji = "speech_balloon";
|
||||
|
||||
await visit("/");
|
||||
await openUserStatusModal();
|
||||
await fillIn(".user-status-description", "some status");
|
||||
|
||||
assert.ok(
|
||||
exists(`.btn-emoji img.emoji[title=${defaultStatusEmoji}]`),
|
||||
"default status emoji is shown"
|
||||
);
|
||||
});
|
||||
|
||||
test("shows actual status on the modal after canceling the modal", async function (assert) {
|
||||
this.siteSettings.enable_user_status = true;
|
||||
|
||||
updateCurrentUser({
|
||||
status: { description: userStatus, emoji: userStatusEmoji },
|
||||
});
|
||||
|
||||
await visit("/");
|
||||
await openUserStatusModal();
|
||||
await fillIn(".user-status-description", "another status");
|
||||
await pickEmoji("cold_face"); // another emoji
|
||||
await click(".d-modal-cancel");
|
||||
await openUserStatusModal();
|
||||
|
||||
assert.equal(
|
||||
query(`.btn-emoji img.emoji`).title,
|
||||
userStatusEmoji,
|
||||
"the actual status emoji is shown"
|
||||
);
|
||||
assert.equal(
|
||||
query(".user-status-description").value,
|
||||
userStatus,
|
||||
"the actual status description is shown"
|
||||
);
|
||||
});
|
||||
|
||||
test("shows the trash button when editing status that was set before", async function (assert) {
|
||||
this.siteSettings.enable_user_status = true;
|
||||
updateCurrentUser({ status: { description: userStatus } });
|
||||
|
||||
await visit("/");
|
||||
await click(".header-dropdown-toggle.current-user");
|
||||
await click(".menu-links-row .user-preferences-link");
|
||||
await click(".user-status button");
|
||||
await openUserStatusModal();
|
||||
|
||||
assert.ok(exists(".btn.delete-status"));
|
||||
});
|
||||
|
@ -167,10 +278,28 @@ acceptance("User Status", function (needs) {
|
|||
updateCurrentUser({ status: null });
|
||||
|
||||
await visit("/");
|
||||
await click(".header-dropdown-toggle.current-user");
|
||||
await click(".menu-links-row .user-preferences-link");
|
||||
await click(".user-status button");
|
||||
await openUserStatusModal();
|
||||
|
||||
assert.notOk(exists(".btn.delete-status"));
|
||||
});
|
||||
|
||||
test("shows empty modal after deleting the status", async function (assert) {
|
||||
this.siteSettings.enable_user_status = true;
|
||||
|
||||
updateCurrentUser({
|
||||
status: { description: userStatus, emoji: userStatusEmoji },
|
||||
});
|
||||
|
||||
await visit("/");
|
||||
await openUserStatusModal();
|
||||
await click(".btn.delete-status");
|
||||
await openUserStatusModal();
|
||||
|
||||
assert.ok(exists(`.d-icon-discourse-emojis`), "empty status icon is shown");
|
||||
assert.equal(
|
||||
query(".user-status-description").value,
|
||||
"",
|
||||
"no status description is shown"
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
@import "time-shortcut-picker";
|
||||
@import "user-card";
|
||||
@import "user-info";
|
||||
@import "user-status-picker";
|
||||
@import "user-stream-item";
|
||||
@import "user-stream";
|
||||
@import "widget-dropdown";
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
.user-status-picker-wrap {
|
||||
display: inline-flex;
|
||||
width: 100%;
|
||||
align-items: end;
|
||||
|
||||
.user-status-picker {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
border: 1px solid var(--primary-medium);
|
||||
|
||||
.btn-emoji {
|
||||
margin: 3px;
|
||||
width: 2.3em;
|
||||
text-align: center;
|
||||
|
||||
.svg-icon {
|
||||
color: var(--primary-high);
|
||||
}
|
||||
}
|
||||
|
||||
.user-status-description {
|
||||
width: 100%;
|
||||
margin-bottom: 0;
|
||||
border: none;
|
||||
outline: none;
|
||||
padding-left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.user-status-picker.focused {
|
||||
border: 1px solid var(--tertiary);
|
||||
outline: 1px solid var(--tertiary);
|
||||
}
|
||||
}
|
|
@ -22,17 +22,5 @@
|
|||
@media (max-width: 600px) {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.ember-text-field.user-status-description {
|
||||
min-width: 220px;
|
||||
width: 100%;
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
||||
.user-status-description-wrap {
|
||||
display: inline-flex;
|
||||
width: 100%;
|
||||
align-items: end;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,9 +5,10 @@ class UserStatusController < ApplicationController
|
|||
|
||||
def set
|
||||
ensure_feature_enabled
|
||||
raise Discourse::InvalidParameters.new(:description) if params[:description].blank?
|
||||
description = params.require(:description)
|
||||
emoji = params.require(:emoji)
|
||||
|
||||
current_user.set_status!(params[:description])
|
||||
current_user.set_status!(description, emoji)
|
||||
render json: success_json
|
||||
end
|
||||
|
||||
|
|
|
@ -1522,14 +1522,18 @@ class User < ActiveRecord::Base
|
|||
publish_user_status(nil)
|
||||
end
|
||||
|
||||
def set_status!(description)
|
||||
def set_status!(description, emoji)
|
||||
now = Time.zone.now
|
||||
if user_status
|
||||
user_status.update!(description: description, set_at: now)
|
||||
user_status.update!(
|
||||
description: description,
|
||||
emoji: emoji,
|
||||
set_at: now)
|
||||
else
|
||||
self.user_status = UserStatus.create!(
|
||||
user_id: id,
|
||||
description: description,
|
||||
emoji: emoji,
|
||||
set_at: now
|
||||
)
|
||||
end
|
||||
|
|
|
@ -18,7 +18,7 @@ end
|
|||
# Table name: user_statuses
|
||||
#
|
||||
# user_id :integer not null, primary key
|
||||
# emoji :string
|
||||
# emoji :string not null
|
||||
# description :string not null
|
||||
# set_at :datetime not null
|
||||
# ends_at :datetime
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class DisallowNullEmojiOnUserStatus < ActiveRecord::Migration[7.0]
|
||||
def up
|
||||
execute "UPDATE user_statuses SET emoji = 'speech_balloon'"
|
||||
change_column :user_statuses, :emoji, :string, null: false
|
||||
end
|
||||
|
||||
def down
|
||||
change_column :user_statuses, :emoji, :string, null: true
|
||||
end
|
||||
end
|
|
@ -25,32 +25,46 @@ describe UserStatusController do
|
|||
SiteSetting.enable_user_status = true
|
||||
end
|
||||
|
||||
it "sets user status" do
|
||||
status = "off to dentist"
|
||||
put "/user-status.json", params: { description: status }
|
||||
expect(user.user_status.description).to eq(status)
|
||||
it 'the description parameter is mandatory' do
|
||||
put "/user-status.json", params: { emoji: "tooth" }
|
||||
expect(response.status).to eq(400)
|
||||
end
|
||||
|
||||
it 'the description parameter is mandatory' do
|
||||
put "/user-status.json", params: {}
|
||||
it 'the emoji parameter is mandatory' do
|
||||
put "/user-status.json", params: { description: "off to dentist" }
|
||||
expect(response.status).to eq(400)
|
||||
end
|
||||
|
||||
it "sets user status" do
|
||||
status = "off to dentist"
|
||||
status_emoji = "tooth"
|
||||
put "/user-status.json", params: { description: status, emoji: status_emoji }
|
||||
expect(user.user_status.description).to eq(status)
|
||||
expect(user.user_status.emoji).to eq(status_emoji)
|
||||
end
|
||||
|
||||
it "following calls update status" do
|
||||
status = "off to dentist"
|
||||
put "/user-status.json", params: { description: status }
|
||||
status_emoji = "tooth"
|
||||
put "/user-status.json", params: { description: status, emoji: status_emoji }
|
||||
user.reload
|
||||
expect(user.user_status.description).to eq(status)
|
||||
expect(user.user_status.emoji).to eq(status_emoji)
|
||||
|
||||
new_status = "working"
|
||||
put "/user-status.json", params: { description: new_status }
|
||||
new_status = "surfing"
|
||||
new_status_emoji = "surfing_man"
|
||||
put "/user-status.json", params: { description: new_status, emoji: new_status_emoji }
|
||||
user.reload
|
||||
expect(user.user_status.description).to eq(new_status)
|
||||
expect(user.user_status.emoji).to eq(new_status_emoji)
|
||||
end
|
||||
|
||||
it "publishes to message bus" do
|
||||
status = "off to dentist"
|
||||
messages = MessageBus.track_publish { put "/user-status.json", params: { description: status } }
|
||||
emoji = "tooth"
|
||||
messages = MessageBus.track_publish do
|
||||
put "/user-status.json", params: { description: status, emoji: emoji }
|
||||
end
|
||||
|
||||
expect(messages.size).to eq(1)
|
||||
expect(messages[0].channel).to eq("/user-status/#{user.id}")
|
||||
|
|
Loading…
Reference in New Issue