test(HH-558): complete WebChannel sender display regression matrix (#141)
* chore(agent): baseline — uncommitted work from the local directory * test(HH-558): cover widget sender display matrix --------- Co-authored-by: Rogee <rogee@ipao.vip>
This commit is contained in:
@@ -8,6 +8,8 @@ import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
@@ -416,7 +418,7 @@ func TestHub_SendToAccountSanitizesVisitorIdentity(t *testing.T) {
|
||||
hub.subscribeClient(visitor.ID, accountRoomName(10))
|
||||
visitor.SubscribedRooms[accountRoomName(10)] = true
|
||||
|
||||
hub.SendToAccount(10, []byte(`{"event":"message.created","data":{"content":"same reply","sender_type":"AgentBot","sender_id":7,"ai_takeover_active":true,"additional_attributes":{"agent_name":"Captain"}}}`))
|
||||
hub.SendToAccount(10, []byte(`{"event":"message.created","data":{"content":"same reply","message_type":"outgoing","sender":{"available_name":"Captain","name":"Captain","agent_name":"Captain"},"sender_type":"AgentBot","sender_id":7,"ai_takeover_active":true,"additional_attributes":{"agent_name":"Captain","sender_name":"Captain"}}}`))
|
||||
|
||||
var agentMessage, visitorMessage []byte
|
||||
select {
|
||||
@@ -438,6 +440,31 @@ func TestHub_SendToAccountSanitizesVisitorIdentity(t *testing.T) {
|
||||
assert.NotContains(t, string(visitorMessage), "Captain")
|
||||
}
|
||||
|
||||
func TestEventDataForClient_VisitorMessageKeepsPublicFieldsOnly(t *testing.T) {
|
||||
hub := NewHubSimple()
|
||||
visitor := NewClient(2, 10, nil, hub)
|
||||
visitor.IsContact = true
|
||||
|
||||
data := eventDataForClient(visitor, []byte(`{"event":"message.created","data":{"id":12,"content":"Dashboard reply","message_type":1,"conversation_id":42,"sender":{"available_name":"Captain","name":"Captain","agent_name":"Captain"},"sender_type":"AgentBot","sender_id":7,"ai_takeover_active":true,"additional_attributes":{"sender_name":"Captain","agent_name":"Captain"}}}`))
|
||||
fixture, err := os.ReadFile(filepath.Join("..", "..", "..", "..", "frontend", "testdata", "visitor_ws_payload.json"))
|
||||
require.NoError(t, err)
|
||||
assert.JSONEq(t, string(fixture), string(data))
|
||||
|
||||
var payload map[string]any
|
||||
require.NoError(t, json.Unmarshal(data, &payload))
|
||||
assert.Equal(t, "message.created", payload["event"])
|
||||
message, ok := payload["data"].(map[string]any)
|
||||
require.True(t, ok)
|
||||
assert.Equal(t, "Dashboard reply", message["content"])
|
||||
assert.Equal(t, float64(1), message["message_type"])
|
||||
assert.Equal(t, float64(42), message["conversation_id"])
|
||||
assert.NotContains(t, message, "sender")
|
||||
assert.NotContains(t, message, "sender_type")
|
||||
assert.NotContains(t, message, "sender_id")
|
||||
assert.NotContains(t, message, "ai_takeover_active")
|
||||
assert.Equal(t, map[string]any{}, message["additional_attributes"])
|
||||
}
|
||||
|
||||
func TestHub_VisitorRoomAndClientDeliverySanitizeIdentity(t *testing.T) {
|
||||
hub := NewHubSimple()
|
||||
visitor := NewClient(2, 10, nil, hub)
|
||||
@@ -809,7 +836,7 @@ func TestServeCable_WidgetReceivesTokenRoomEvent(t *testing.T) {
|
||||
require.NoError(t, json.Unmarshal(confirmation, &confirm))
|
||||
assert.Equal(t, ServerConfirmSubscribe, confirm.Type)
|
||||
|
||||
hub.SendToRoom(pubsubTokenRoomName("visitor-token"), []byte(`{"event":"message.created","data":{"id":12,"content":"Dashboard reply","message_type":1,"conversation_id":42}}`))
|
||||
hub.SendToRoom(pubsubTokenRoomName("visitor-token"), []byte(`{"event":"message.created","data":{"id":12,"content":"Dashboard reply","message_type":1,"conversation_id":42,"sender":{"available_name":"Captain","name":"Captain"},"sender_type":"AgentBot","sender_id":7,"ai_takeover_active":true,"additional_attributes":{"sender_name":"Captain","agent_name":"Captain"}}}`))
|
||||
_, message, err := conn.ReadMessage()
|
||||
require.NoError(t, err)
|
||||
var delivered struct {
|
||||
@@ -825,6 +852,11 @@ func TestServeCable_WidgetReceivesTokenRoomEvent(t *testing.T) {
|
||||
assert.Equal(t, "Dashboard reply", payload["content"])
|
||||
assert.Equal(t, float64(1), payload["message_type"])
|
||||
assert.Equal(t, float64(42), payload["conversation_id"])
|
||||
assert.NotContains(t, payload, "sender")
|
||||
assert.NotContains(t, payload, "sender_type")
|
||||
assert.NotContains(t, payload, "sender_id")
|
||||
assert.NotContains(t, payload, "ai_takeover_active")
|
||||
assert.Equal(t, map[string]interface{}{}, payload["additional_attributes"])
|
||||
}
|
||||
|
||||
func TestDashboardOutgoingReachesDashboardAndReconnectedWidget(t *testing.T) {
|
||||
|
||||
@@ -43,6 +43,14 @@ services:
|
||||
- "8025:8025" # Web UI
|
||||
# Reference: Chatwoot docker-compose includes mailhog for email testing
|
||||
|
||||
web-channel-test:
|
||||
image: nginx:alpine
|
||||
container_name: gochat-web-channel-test
|
||||
ports:
|
||||
- "8081:80"
|
||||
volumes:
|
||||
- ./web-channel-test/index.html:/usr/share/nginx/html/index.html:ro
|
||||
|
||||
gochat:
|
||||
build:
|
||||
context: ../..
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
<!doctype html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>GoChat WEB CHANNEL 测试</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>GoChat WEB CHANNEL 测试</h1>
|
||||
<script>
|
||||
window.chatwootSettings = { "position": "right", "type": "standard", "launcherTitle": "" };
|
||||
(function (d, t) {
|
||||
var BASE_URL = "https://gochat.yqbmb.com";
|
||||
var g = d.createElement(t), s = d.getElementsByTagName(t)[0];
|
||||
g.src = BASE_URL + "/sdk/js/sdk.js";
|
||||
g.async = true;
|
||||
s.parentNode.insertBefore(g, s);
|
||||
g.onload = function () {
|
||||
window.chatwootSDK.run({
|
||||
websiteToken: "1e26e9f9866a6e7d988d85fa",
|
||||
baseUrl: BASE_URL
|
||||
});
|
||||
};
|
||||
})(document, "script");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,26 +1,113 @@
|
||||
import { mount } from '@vue/test-utils';
|
||||
import VueDOMPurifyHTML from 'vue-dompurify-html';
|
||||
import visitorPayload from '../../../../../testdata/visitor_ws_payload.json';
|
||||
import AgentMessage from '../AgentMessage.vue';
|
||||
import UnreadMessage from '../UnreadMessage.vue';
|
||||
|
||||
const context = {
|
||||
channelConfig: { websiteName: 'GoChat' },
|
||||
channelConfig: {
|
||||
websiteName: 'GoChat',
|
||||
enabledFeatures: [],
|
||||
avatarUrl: '',
|
||||
},
|
||||
useInboxAvatarForBot: false,
|
||||
$t: key => key,
|
||||
};
|
||||
|
||||
describe('widget agent name', () => {
|
||||
it('uses the inbox name when a conversation message has no public sender', () => {
|
||||
expect(
|
||||
AgentMessage.computed.agentName.call({ ...context, message: {} })
|
||||
).toBe('GoChat');
|
||||
window.chatwootWebChannel = context.channelConfig;
|
||||
|
||||
const mountAgentMessage = message =>
|
||||
mount(AgentMessage, {
|
||||
props: {
|
||||
message: { ...message, showAvatar: true },
|
||||
},
|
||||
global: {
|
||||
plugins: [VueDOMPurifyHTML],
|
||||
stubs: {
|
||||
AgentMessageBubble: { template: '<div />' },
|
||||
Avatar: { template: '<div />' },
|
||||
FileBubble: { template: '<div />' },
|
||||
ImageBubble: { template: '<div />' },
|
||||
MessageReplyButton: { template: '<div />' },
|
||||
ReplyToChip: { template: '<div />' },
|
||||
UserMessage: { template: '<div />' },
|
||||
VideoBubble: { template: '<div />' },
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
it('uses the inbox name when an unread message has no public sender', () => {
|
||||
describe('widget agent name', () => {
|
||||
it.each([
|
||||
[
|
||||
'available_name',
|
||||
{
|
||||
sender: { available_name: 'Available', name: 'Name' },
|
||||
additional_attributes: { sender_name: 'Visitor service' },
|
||||
},
|
||||
'Available',
|
||||
],
|
||||
[
|
||||
'name',
|
||||
{
|
||||
sender: { name: 'Name' },
|
||||
additional_attributes: { sender_name: 'Visitor service' },
|
||||
},
|
||||
'Name',
|
||||
],
|
||||
[
|
||||
'message sender_name',
|
||||
{ additional_attributes: { sender_name: 'Visitor service' } },
|
||||
'Visitor service',
|
||||
],
|
||||
['inbox name', {}, 'GoChat'],
|
||||
])('conversation message prefers %s', (_source, message, expected) => {
|
||||
expect(AgentMessage.computed.agentName.call({ ...context, message })).toBe(
|
||||
expected
|
||||
);
|
||||
});
|
||||
|
||||
it('returns an empty name when the sanitized inbox name is unavailable', () => {
|
||||
expect(
|
||||
AgentMessage.computed.agentName.call({
|
||||
...context,
|
||||
channelConfig: { ...context.channelConfig, websiteName: '' },
|
||||
message: {},
|
||||
})
|
||||
).toBe('');
|
||||
});
|
||||
|
||||
it.each([
|
||||
[
|
||||
'available_name',
|
||||
{ available_name: 'Available', name: 'Name' },
|
||||
'Available',
|
||||
],
|
||||
['name', { name: 'Name' }, 'Name'],
|
||||
['inbox name', {}, 'GoChat'],
|
||||
])('unread message prefers %s', (_source, sender, expected) => {
|
||||
expect(
|
||||
UnreadMessage.computed.agentName.call({
|
||||
...context,
|
||||
sender,
|
||||
isSenderExist: UnreadMessage.methods.isSenderExist,
|
||||
})
|
||||
).toBe(expected);
|
||||
});
|
||||
|
||||
it('returns an empty unread name when the inbox name is unavailable', () => {
|
||||
expect(
|
||||
UnreadMessage.computed.agentName.call({
|
||||
...context,
|
||||
channelConfig: { ...context.channelConfig, websiteName: '' },
|
||||
sender: {},
|
||||
isSenderExist: UnreadMessage.methods.isSenderExist,
|
||||
})
|
||||
).toBe('GoChat');
|
||||
).toBe('');
|
||||
});
|
||||
|
||||
it('mounts the visitor WS output with the inbox name', () => {
|
||||
const wrapper = mountAgentMessage(visitorPayload.data);
|
||||
|
||||
expect(wrapper.get('.agent-name').text()).toBe('GoChat');
|
||||
});
|
||||
});
|
||||
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"event": "message.created",
|
||||
"data": {
|
||||
"id": 12,
|
||||
"content": "Dashboard reply",
|
||||
"message_type": 1,
|
||||
"conversation_id": 42,
|
||||
"additional_attributes": {}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user