Skip to content
This repository has been archived by the owner on Sep 12, 2023. It is now read-only.

Commit

Permalink
Merge pull request #222 from AteKitty07/seen_messages
Browse files Browse the repository at this point in the history
Seen messages
  • Loading branch information
KennethTrecy authored Oct 15, 2022
2 parents 84e0206 + 012fdd1 commit 39e50a0
Show file tree
Hide file tree
Showing 10 changed files with 348 additions and 71 deletions.
1 change: 1 addition & 0 deletions common_front-end/constants/provided_keys.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export const CHAT_MESSAGE_ACTIVITY = Symbol("Key for chat activity resource of current user")
export const CHAT_MESSAGE_ACTIVITIES_IN_CONSULTATION = Symbol("current chat message activity")

export const BODY_CLASSES = Symbol("Key for body CSS manager")
39 changes: 39 additions & 0 deletions common_front-end/external/window_focus.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import type { FocusListener } from "$@/types/dependent"

import Stub from "$/singletons/stub"
import RequestEnvironment from "$/singletons/request_environment"

export default class extends RequestEnvironment {
private static rawListeners: FocusListener[] = []

static addEventListener(listener: FocusListener): void {
this.rawListeners.push(listener)
Stub.runConditionally(
() => {
window.addEventListener("blur", () => {
this.rawListeners.forEach(rawListener => rawListener("blur"))
})
window.addEventListener("focus", () => {
this.rawListeners.forEach(rawListener => rawListener("focus"))
})
},
() => [ {} as unknown as void, {
"arguments": [ listener ],
"functionName": "addEventListener"
} ]
)
}

static emitMockEvent(state: "blur" | "focus"): void {
Stub.runConditionally(
() => {
throw new Error("It is impossible to emit mock events in non-test environments.")
},
() => {
this.rawListeners.forEach(rawListener => rawListener(state))

return [ {} as unknown as void, null ]
}
)
}
}
2 changes: 2 additions & 0 deletions common_front-end/types/dependent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,5 @@ interface TimerListener {
export type TimerListeners = TimerListener[]

export type VisibilityListener = (currentVisibility: Document["visibilityState"]) => void

export type FocusListener = (currentFocus: "focus" | "blur") => void
14 changes: 9 additions & 5 deletions components/consultation/chat_window.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,8 @@ describe("Component: consultation/chat_window", () => {
},
"props": {
"chatMessages": fakeChatMessage,
"consultation": fakeConsultation
"consultation": fakeConsultation,
"isConsultationListShown": false
}
})

Expand Down Expand Up @@ -279,7 +280,8 @@ describe("Component: consultation/chat_window", () => {
},
"props": {
"chatMessages": fakeChatMessage,
"consultation": fakeConsultation
"consultation": fakeConsultation,
"isConsultationListShown": false
}
})

Expand Down Expand Up @@ -325,7 +327,8 @@ describe("Component: consultation/chat_window", () => {
},
"props": {
"chatMessages": fakeChatMessage,
"consultation": fakeConsultation
"consultation": fakeConsultation,
"isConsultationListShown": false
}
})

Expand Down Expand Up @@ -471,7 +474,8 @@ describe("Component: consultation/chat_window", () => {
},
"props": {
"chatMessages": fakeChatMessage,
"consultation": fakeConsultation
"consultation": fakeConsultation,
"isConsultationListShown": false
}
})

Expand Down Expand Up @@ -633,7 +637,7 @@ describe("Component: consultation/chat_window", () => {
})
})

describe.only("chat messages", () => {
describe("chat messages", () => {
it("is sorted properly", () => {
const scheduledStartAt = new Date()
const consultant = {
Expand Down
4 changes: 2 additions & 2 deletions components/consultation/chat_window.vue
Original file line number Diff line number Diff line change
Expand Up @@ -93,10 +93,10 @@
</div>

<div
v-for="message in sortedMessagesByTime"
v-for="(message, i) in sortedMessagesByTime"
:key="message.id"
class="chat-entry">
<ChatMessageItem :chat-message="message"/>
<ChatMessageItem :chat-message="message" :next-message="sortedMessagesByTime[i+1]"/>
</div>
</div>
<UserController
Expand Down
159 changes: 154 additions & 5 deletions components/consultation/chat_window/chat_message_item.spec.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
/* eslint-disable max-lines */
import { shallowMount } from "@vue/test-utils"

import type { TextMessage, StatusMessage } from "$/types/message"
import type { DeserializedUserDocument } from "$/types/documents/user"
import type { DeserializedChatMessageResource } from "$/types/documents/chat_message"

import Component from "./chat_message_item.vue"
import { CHAT_MESSAGE_ACTIVITIES_IN_CONSULTATION } from "$@/constants/provided_keys"
import { DeserializedChatMessageActivityResource } from "$/types/documents/chat_message_activity"

describe("Component: consultation/chat_window/chat_message_item", () => {
describe("Text message", () => {
describe("text message", () => {
const chatMessageActivities = {
"data": []
}

it("should show self's text message properly", () => {
const CURRENT_TIME = new Date()
const user = {
Expand All @@ -32,6 +40,7 @@ describe("Component: consultation/chat_window/chat_message_item", () => {
"provide": {
"pageContext": {
"pageProps": {
chatMessageActivities,
"userProfile": user
}
}
Expand Down Expand Up @@ -63,7 +72,7 @@ describe("Component: consultation/chat_window/chat_message_item", () => {
const messageItemProfilePicture = wrapper.find(".message-item .self")

expect(messageItem.find(".self").exists()).toBeTruthy()
expect(messageItemContent.html()).toContain(textValue)
expect(messageItemContent.text()).toContain(textValue)
expect(messageItemProfilePicture.exists()).toBeTruthy()
expect(messageItemProfilePicture.attributes("title")).toEqual(user.data.name)
})
Expand Down Expand Up @@ -110,6 +119,7 @@ describe("Component: consultation/chat_window/chat_message_item", () => {
"provide": {
"pageContext": {
"pageProps": {
chatMessageActivities,
"userProfile": user
}
}
Expand Down Expand Up @@ -147,7 +157,71 @@ describe("Component: consultation/chat_window/chat_message_item", () => {
})
})

describe("Status message", () => {
describe("status message", () => {
const chatMessageActivities = {
"data": []
}

it("should show own status message properly", () => {
const CURRENT_TIME = new Date()
const user = {
"data": {
"email": "",
"id": "1",
"kind": "reachable_employee",
"name": "self",
"prefersDark": true,
"profilePicture": {
"data": {
"fileContents": "http://example.com/image_a",
"id": "1",
"type": "profile_picture"
}
},
"type": "user"
}
} as DeserializedUserDocument<"profilePicture">
const textValue = "Hello foo!"
const wrapper = shallowMount<any>(Component, {
"global": {
"provide": {
"pageContext": {
"pageProps": {
chatMessageActivities,
"userProfile": user
}
}
},
"stubs": {
"ProfilePicture": {
"name": "ProfilePicture",
"template": "<img/>"
}
}
},
"props": {
"chatMessage": {
"createdAt": CURRENT_TIME,
"data": {
"value": textValue
},
"id": "0",
"kind": "status",
"type": "chat_message",
"updatedAt": CURRENT_TIME,
user
} as DeserializedChatMessageResource<"user"> & StatusMessage<"deserialized">
}
})

const messageItem = wrapper.find(".message-item")
const messageItemContent = wrapper.find(".message-item-content")

expect(messageItem.classes()).toContain("status-message")
expect(messageItemContent.html()).toContain(textValue)
expect(messageItemContent.html()).toContain(user.data.name)
})

it("should show other's status message properly", () => {
const CURRENT_TIME = new Date()
const user = {
Expand Down Expand Up @@ -190,6 +264,7 @@ describe("Component: consultation/chat_window/chat_message_item", () => {
"provide": {
"pageContext": {
"pageProps": {
chatMessageActivities,
"userProfile": user
}
}
Expand Down Expand Up @@ -225,7 +300,11 @@ describe("Component: consultation/chat_window/chat_message_item", () => {
})
})

describe("File message", () => {
describe("file message", () => {
const chatMessageActivities = {
"data": []
}

it("can show image type message properly", () => {
const CURRENT_TIME = new Date()
const user = {
Expand Down Expand Up @@ -254,6 +333,7 @@ describe("Component: consultation/chat_window/chat_message_item", () => {
"provide": {
"pageContext": {
"pageProps": {
chatMessageActivities,
"userProfile": user
}
}
Expand Down Expand Up @@ -292,7 +372,7 @@ describe("Component: consultation/chat_window/chat_message_item", () => {
expect(actualFile.attributes("src")).toBeDefined()
})

it("can show image type message properly", () => {
it("can show file type message properly", () => {
const CURRENT_TIME = new Date()
const user = {
"data": {
Expand Down Expand Up @@ -320,6 +400,7 @@ describe("Component: consultation/chat_window/chat_message_item", () => {
"provide": {
"pageContext": {
"pageProps": {
chatMessageActivities,
"userProfile": user
}
}
Expand Down Expand Up @@ -358,4 +439,72 @@ describe("Component: consultation/chat_window/chat_message_item", () => {
expect(actualFile.attributes("href")).toBeDefined()
})
})

describe("seen users", () => {
it("can identify which users have seen latest message", () => {
const CURRENT_TIME = new Date("2022-10-4 10:00:00")
const user = {
"data": {
"email": "",
"id": "1",
"kind": "reachable_employee",
"name": "A",
"prefersDark": true,
"profilePicture": {
"data": {
"fileContents": "http://example.com/image_a",
"id": "1",
"type": "profile_picture"
}
},
"type": "user"
}
} as DeserializedUserDocument<"profilePicture">
const data = {
"value": "hello world"
}
const chatMessageActivities = [
{
"id": 0,
"receivedMessageAt": new Date("2022-10-4 10:00:01"),
"seenMessageAt": new Date("2022-10-4 10:01:03"),
"type": "chat_message_activity",
user
} as unknown as DeserializedChatMessageActivityResource
]
const wrapper = shallowMount<any>(Component, {
"global": {
"provide": {
[CHAT_MESSAGE_ACTIVITIES_IN_CONSULTATION]: chatMessageActivities,
"pageContext": {
"pageProps": {
"userProfile": user
}
}
},
"stubs": {
"ProfilePicture": {
"name": "ProfilePicture",
"template": "<img/>"
}
}
},
"props": {
"chatMessage": {
"createdAt": CURRENT_TIME,
data,
"id": "0",
"kind": "text",
"type": "chat_message",
"updatedAt": CURRENT_TIME,
user
}
}
})
const seenList = wrapper.find(".seen-list")
const seenUser = seenList.find("img")

expect(seenUser.exists()).toBeTruthy()
})
})
})
Loading

0 comments on commit 39e50a0

Please sign in to comment.