Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
converse.js
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
converse.js
Commits
8b93e0f7
Commit
8b93e0f7
authored
Aug 14, 2019
by
JC Brand
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Move MUC message tests to spec/muc_messages.js
parent
fa59b22f
Changes
3
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
853 additions
and
842 deletions
+853
-842
spec/messages.js
spec/messages.js
+0
-842
spec/muc_messages.js
spec/muc_messages.js
+852
-0
tests/runner.js
tests/runner.js
+1
-0
No files found.
spec/messages.js
View file @
8b93e0f7
...
...
@@ -2256,846 +2256,4 @@
done
();
}));
});
describe
(
"
A Groupchat Message
"
,
function
()
{
it
(
"
is specially marked when you are mentioned in it
"
,
mock
.
initConverse
(
null
,
[
'
rosterGroupsFetched
'
,
'
chatBoxesFetched
'
],
{},
async
function
(
done
,
_converse
)
{
const
muc_jid
=
'
lounge@montague.lit
'
;
await
test_utils
.
openAndEnterChatRoom
(
_converse
,
muc_jid
,
'
romeo
'
);
const
view
=
_converse
.
api
.
chatviews
.
get
(
muc_jid
);
if
(
!
view
.
el
.
querySelectorAll
(
'
.chat-area
'
).
length
)
{
view
.
renderChatArea
();
}
const
message
=
'
romeo: Your attention is required
'
;
const
nick
=
mock
.
chatroom_names
[
0
],
msg
=
$msg
({
from
:
'
lounge@montague.lit/
'
+
nick
,
id
:
(
new
Date
()).
getTime
(),
to
:
'
romeo@montague.lit
'
,
type
:
'
groupchat
'
}).
c
(
'
body
'
).
t
(
message
).
tree
();
await
view
.
model
.
onMessage
(
msg
);
await
new
Promise
((
resolve
,
reject
)
=>
view
.
once
(
'
messageInserted
'
,
resolve
));
expect
(
u
.
hasClass
(
'
mentioned
'
,
view
.
el
.
querySelector
(
'
.chat-msg
'
))).
toBeTruthy
();
done
();
}));
it
(
"
can not be expected to have a unique id attribute
"
,
mock
.
initConverse
(
null
,
[
'
rosterGroupsFetched
'
,
'
chatBoxesFetched
'
],
{},
async
function
(
done
,
_converse
)
{
const
muc_jid
=
'
lounge@montague.lit
'
;
await
test_utils
.
openAndEnterChatRoom
(
_converse
,
muc_jid
,
'
romeo
'
);
const
view
=
_converse
.
api
.
chatviews
.
get
(
muc_jid
);
if
(
!
view
.
el
.
querySelectorAll
(
'
.chat-area
'
).
length
)
{
view
.
renderChatArea
();
}
const
id
=
u
.
getUniqueId
();
let
msg
=
$msg
({
from
:
'
lounge@montague.lit/some1
'
,
id
:
id
,
to
:
'
romeo@montague.lit
'
,
type
:
'
groupchat
'
}).
c
(
'
body
'
).
t
(
'
First message
'
).
tree
();
await
view
.
model
.
onMessage
(
msg
);
await
new
Promise
((
resolve
,
reject
)
=>
view
.
once
(
'
messageInserted
'
,
resolve
));
expect
(
view
.
el
.
querySelectorAll
(
'
.chat-msg
'
).
length
).
toBe
(
1
);
msg
=
$msg
({
from
:
'
lounge@montague.lit/some2
'
,
id
:
id
,
to
:
'
romeo@montague.lit
'
,
type
:
'
groupchat
'
}).
c
(
'
body
'
).
t
(
'
Another message
'
).
tree
();
await
view
.
model
.
onMessage
(
msg
);
await
new
Promise
((
resolve
,
reject
)
=>
view
.
once
(
'
messageInserted
'
,
resolve
));
expect
(
view
.
el
.
querySelectorAll
(
'
.chat-msg
'
).
length
).
toBe
(
2
);
done
();
}));
it
(
"
is ignored if it has the same stanza-id of an already received on
"
,
mock
.
initConverse
(
null
,
[
'
rosterGroupsFetched
'
],
{},
async
function
(
done
,
_converse
)
{
const
muc_jid
=
'
room@muc.example.com
'
;
await
test_utils
.
openAndEnterChatRoom
(
_converse
,
muc_jid
,
'
romeo
'
);
const
view
=
_converse
.
api
.
chatviews
.
get
(
muc_jid
);
spyOn
(
view
.
model
,
'
findDuplicateFromStanzaID
'
).
and
.
callThrough
();
let
stanza
=
u
.
toStanza
(
`
<message xmlns="jabber:client"
from="room@muc.example.com/some1"
to="
${
_converse
.
connection
.
jid
}
"
type="groupchat">
<body>Typical body text</body>
<stanza-id xmlns="urn:xmpp:sid:0"
id="5f3dbc5e-e1d3-4077-a492-693f3769c7ad"
by="room@muc.example.com"/>
</message>`
);
_converse
.
connection
.
_dataRecv
(
test_utils
.
createRequest
(
stanza
));
await
u
.
waitUntil
(()
=>
_converse
.
api
.
chats
.
get
().
length
);
await
u
.
waitUntil
(()
=>
view
.
model
.
messages
.
length
===
1
);
await
u
.
waitUntil
(()
=>
view
.
model
.
findDuplicateFromStanzaID
.
calls
.
count
()
===
1
);
let
result
=
await
view
.
model
.
findDuplicateFromStanzaID
.
calls
.
all
()[
0
].
returnValue
;
expect
(
result
).
toBe
(
undefined
);
stanza
=
u
.
toStanza
(
`
<message xmlns="jabber:client"
from="room@muc.example.com/some1"
to="
${
_converse
.
connection
.
jid
}
"
type="groupchat">
<body>Typical body text</body>
<stanza-id xmlns="urn:xmpp:sid:0"
id="5f3dbc5e-e1d3-4077-a492-693f3769c7ad"
by="room@muc.example.com"/>
</message>`
);
spyOn
(
view
.
model
,
'
updateMessage
'
);
_converse
.
connection
.
_dataRecv
(
test_utils
.
createRequest
(
stanza
));
await
u
.
waitUntil
(()
=>
view
.
model
.
findDuplicateFromStanzaID
.
calls
.
count
()
===
2
);
result
=
await
view
.
model
.
findDuplicateFromStanzaID
.
calls
.
all
()[
1
].
returnValue
;
expect
(
result
instanceof
_converse
.
Message
).
toBe
(
true
);
expect
(
view
.
model
.
messages
.
length
).
toBe
(
1
);
await
u
.
waitUntil
(()
=>
view
.
model
.
updateMessage
.
calls
.
count
());
done
();
}));
it
(
"
keeps track of the sender's role and affiliation
"
,
mock
.
initConverse
(
null
,
[
'
rosterGroupsFetched
'
],
{},
async
function
(
done
,
_converse
)
{
const
muc_jid
=
'
lounge@montague.lit
'
;
await
test_utils
.
openAndEnterChatRoom
(
_converse
,
muc_jid
,
'
romeo
'
);
const
view
=
_converse
.
api
.
chatviews
.
get
(
muc_jid
);
let
msg
=
$msg
({
from
:
'
lounge@montague.lit/romeo
'
,
id
:
(
new
Date
()).
getTime
(),
to
:
'
romeo@montague.lit
'
,
type
:
'
groupchat
'
}).
c
(
'
body
'
).
t
(
'
I wrote this message!
'
).
tree
();
await
view
.
model
.
onMessage
(
msg
);
await
new
Promise
((
resolve
,
reject
)
=>
view
.
once
(
'
messageInserted
'
,
resolve
));
expect
(
view
.
model
.
messages
.
last
().
occupant
.
get
(
'
affiliation
'
)).
toBe
(
'
owner
'
);
expect
(
view
.
model
.
messages
.
last
().
occupant
.
get
(
'
role
'
)).
toBe
(
'
moderator
'
);
expect
(
view
.
el
.
querySelectorAll
(
'
.chat-msg
'
).
length
).
toBe
(
1
);
expect
(
sizzle
(
'
.chat-msg
'
,
view
.
el
).
pop
().
classList
.
value
.
trim
()).
toBe
(
'
message chat-msg groupchat moderator owner
'
);
let
presence
=
$pres
({
to
:
'
romeo@montague.lit/orchard
'
,
from
:
'
lounge@montague.lit/romeo
'
,
id
:
u
.
getUniqueId
()
}).
c
(
'
x
'
).
attrs
({
xmlns
:
'
http://jabber.org/protocol/muc#user
'
})
.
c
(
'
item
'
).
attrs
({
affiliation
:
'
member
'
,
jid
:
'
romeo@montague.lit/orchard
'
,
role
:
'
participant
'
}).
up
()
.
c
(
'
status
'
).
attrs
({
code
:
'
110
'
}).
up
()
.
c
(
'
status
'
).
attrs
({
code
:
'
210
'
}).
nodeTree
;
_converse
.
connection
.
_dataRecv
(
test_utils
.
createRequest
(
presence
));
msg
=
$msg
({
from
:
'
lounge@montague.lit/romeo
'
,
id
:
(
new
Date
()).
getTime
(),
to
:
'
romeo@montague.lit
'
,
type
:
'
groupchat
'
}).
c
(
'
body
'
).
t
(
'
Another message!
'
).
tree
();
await
view
.
model
.
onMessage
(
msg
);
await
new
Promise
((
resolve
,
reject
)
=>
view
.
once
(
'
messageInserted
'
,
resolve
));
expect
(
view
.
model
.
messages
.
last
().
occupant
.
get
(
'
affiliation
'
)).
toBe
(
'
member
'
);
expect
(
view
.
model
.
messages
.
last
().
occupant
.
get
(
'
role
'
)).
toBe
(
'
participant
'
);
expect
(
view
.
el
.
querySelectorAll
(
'
.chat-msg
'
).
length
).
toBe
(
2
);
expect
(
sizzle
(
'
.chat-msg
'
,
view
.
el
).
pop
().
classList
.
value
.
trim
()).
toBe
(
'
message chat-msg groupchat participant member
'
);
presence
=
$pres
({
to
:
'
romeo@montague.lit/orchard
'
,
from
:
'
lounge@montague.lit/romeo
'
,
id
:
u
.
getUniqueId
()
}).
c
(
'
x
'
).
attrs
({
xmlns
:
'
http://jabber.org/protocol/muc#user
'
})
.
c
(
'
item
'
).
attrs
({
affiliation
:
'
owner
'
,
jid
:
'
romeo@montague.lit/orchard
'
,
role
:
'
moderator
'
}).
up
()
.
c
(
'
status
'
).
attrs
({
code
:
'
110
'
}).
up
()
.
c
(
'
status
'
).
attrs
({
code
:
'
210
'
}).
nodeTree
;
_converse
.
connection
.
_dataRecv
(
test_utils
.
createRequest
(
presence
));
view
.
model
.
sendMessage
(
'
hello world
'
);
await
u
.
waitUntil
(()
=>
view
.
el
.
querySelectorAll
(
'
.chat-msg
'
).
length
===
3
);
expect
(
view
.
model
.
messages
.
last
().
occupant
.
get
(
'
affiliation
'
)).
toBe
(
'
owner
'
);
expect
(
view
.
model
.
messages
.
last
().
occupant
.
get
(
'
role
'
)).
toBe
(
'
moderator
'
);
expect
(
view
.
el
.
querySelectorAll
(
'
.chat-msg
'
).
length
).
toBe
(
3
);
expect
(
sizzle
(
'
.chat-msg
'
,
view
.
el
).
pop
().
classList
.
value
.
trim
()).
toBe
(
'
message chat-msg groupchat moderator owner
'
);
done
();
}));
it
(
"
keeps track whether you are the sender or not
"
,
mock
.
initConverse
(
null
,
[
'
rosterGroupsFetched
'
],
{},
async
function
(
done
,
_converse
)
{
const
muc_jid
=
'
lounge@montague.lit
'
;
await
test_utils
.
openAndEnterChatRoom
(
_converse
,
muc_jid
,
'
romeo
'
);
const
view
=
_converse
.
api
.
chatviews
.
get
(
muc_jid
);
const
msg
=
$msg
({
from
:
'
lounge@montague.lit/romeo
'
,
id
:
(
new
Date
()).
getTime
(),
to
:
'
romeo@montague.lit
'
,
type
:
'
groupchat
'
}).
c
(
'
body
'
).
t
(
'
I wrote this message!
'
).
tree
();
await
view
.
model
.
onMessage
(
msg
);
await
new
Promise
((
resolve
,
reject
)
=>
view
.
once
(
'
messageInserted
'
,
resolve
));
expect
(
view
.
model
.
messages
.
last
().
get
(
'
sender
'
)).
toBe
(
'
me
'
);
done
();
}));
it
(
"
can be replaced with a correction
"
,
mock
.
initConverse
(
null
,
[
'
rosterGroupsFetched
'
],
{},
async
function
(
done
,
_converse
)
{
const
muc_jid
=
'
lounge@montague.lit
'
;
await
test_utils
.
openAndEnterChatRoom
(
_converse
,
muc_jid
,
'
romeo
'
);
const
view
=
_converse
.
api
.
chatviews
.
get
(
muc_jid
);
const
stanza
=
$pres
({
to
:
'
romeo@montague.lit/_converse.js-29092160
'
,
from
:
'
coven@chat.shakespeare.lit/newguy
'
})
.
c
(
'
x
'
,
{
xmlns
:
Strophe
.
NS
.
MUC_USER
})
.
c
(
'
item
'
,
{
'
affiliation
'
:
'
none
'
,
'
jid
'
:
'
newguy@montague.lit/_converse.js-290929789
'
,
'
role
'
:
'
participant
'
}).
tree
();
_converse
.
connection
.
_dataRecv
(
test_utils
.
createRequest
(
stanza
));
const
msg_id
=
u
.
getUniqueId
();
await
view
.
model
.
onMessage
(
$msg
({
'
from
'
:
'
lounge@montague.lit/newguy
'
,
'
to
'
:
_converse
.
connection
.
jid
,
'
type
'
:
'
groupchat
'
,
'
id
'
:
msg_id
,
}).
c
(
'
body
'
).
t
(
'
But soft, what light through yonder airlock breaks?
'
).
tree
());
await
new
Promise
((
resolve
,
reject
)
=>
view
.
once
(
'
messageInserted
'
,
resolve
));
expect
(
view
.
el
.
querySelectorAll
(
'
.chat-msg
'
).
length
).
toBe
(
1
);
expect
(
view
.
el
.
querySelector
(
'
.chat-msg__text
'
).
textContent
)
.
toBe
(
'
But soft, what light through yonder airlock breaks?
'
);
await
view
.
model
.
onMessage
(
$msg
({
'
from
'
:
'
lounge@montague.lit/newguy
'
,
'
to
'
:
_converse
.
connection
.
jid
,
'
type
'
:
'
groupchat
'
,
'
id
'
:
u
.
getUniqueId
(),
}).
c
(
'
body
'
).
t
(
'
But soft, what light through yonder chimney breaks?
'
).
up
()
.
c
(
'
replace
'
,
{
'
id
'
:
msg_id
,
'
xmlns
'
:
'
urn:xmpp:message-correct:0
'
}).
tree
());
await
u
.
waitUntil
(()
=>
view
.
el
.
querySelector
(
'
.chat-msg__text
'
).
textContent
===
'
But soft, what light through yonder chimney breaks?
'
,
500
);
expect
(
view
.
el
.
querySelectorAll
(
'
.chat-msg
'
).
length
).
toBe
(
1
);
expect
(
view
.
el
.
querySelectorAll
(
'
.chat-msg__content .fa-edit
'
).
length
).
toBe
(
1
);
await
view
.
model
.
onMessage
(
$msg
({
'
from
'
:
'
lounge@montague.lit/newguy
'
,
'
to
'
:
_converse
.
connection
.
jid
,
'
type
'
:
'
groupchat
'
,
'
id
'
:
u
.
getUniqueId
(),
}).
c
(
'
body
'
).
t
(
'
But soft, what light through yonder window breaks?
'
).
up
()
.
c
(
'
replace
'
,
{
'
id
'
:
msg_id
,
'
xmlns
'
:
'
urn:xmpp:message-correct:0
'
}).
tree
());
await
u
.
waitUntil
(()
=>
view
.
el
.
querySelector
(
'
.chat-msg__text
'
).
textContent
===
'
But soft, what light through yonder window breaks?
'
,
500
);
expect
(
view
.
el
.
querySelectorAll
(
'
.chat-msg
'
).
length
).
toBe
(
1
);
expect
(
view
.
el
.
querySelectorAll
(
'
.chat-msg__content .fa-edit
'
).
length
).
toBe
(
1
);
view
.
el
.
querySelector
(
'
.chat-msg__content .fa-edit
'
).
click
();
const
modal
=
view
.
model
.
messages
.
at
(
0
).
message_versions_modal
;
await
u
.
waitUntil
(()
=>
u
.
isVisible
(
modal
.
el
),
1000
);
const
older_msgs
=
modal
.
el
.
querySelectorAll
(
'
.older-msg
'
);
expect
(
older_msgs
.
length
).
toBe
(
2
);
expect
(
older_msgs
[
0
].
childNodes
[
1
].
textContent
).
toBe
(
'
: But soft, what light through yonder airlock breaks?
'
);
expect
(
older_msgs
[
0
].
childNodes
[
0
].
nodeName
).
toBe
(
'
TIME
'
);
expect
(
older_msgs
[
1
].
childNodes
[
0
].
nodeName
).
toBe
(
'
TIME
'
);
expect
(
older_msgs
[
1
].
childNodes
[
1
].
textContent
).
toBe
(
'
: But soft, what light through yonder chimney breaks?
'
);
done
();
}));
it
(
"
can be sent as a correction by using the up arrow
"
,
mock
.
initConverse
(
null
,
[
'
rosterGroupsFetched
'
],
{},
async
function
(
done
,
_converse
)
{
const
muc_jid
=
'
lounge@montague.lit
'
;
await
test_utils
.
openAndEnterChatRoom
(
_converse
,
muc_jid
,
'
romeo
'
);
const
view
=
_converse
.
api
.
chatviews
.
get
(
muc_jid
);
const
textarea
=
view
.
el
.
querySelector
(
'
textarea.chat-textarea
'
);
expect
(
textarea
.
value
).
toBe
(
''
);
view
.
onKeyDown
({
target
:
textarea
,
keyCode
:
38
// Up arrow
});
expect
(
textarea
.
value
).
toBe
(
''
);
textarea
.
value
=
'
But soft, what light through yonder airlock breaks?
'
;
view
.
onKeyDown
({
target
:
textarea
,
preventDefault
:
function
preventDefault
()
{},
keyCode
:
13
// Enter
});
await
new
Promise
((
resolve
,
reject
)
=>
view
.
once
(
'
messageInserted
'
,
resolve
));
expect
(
view
.
el
.
querySelectorAll
(
'
.chat-msg
'
).
length
).
toBe
(
1
);
expect
(
view
.
el
.
querySelector
(
'
.chat-msg__text
'
).
textContent
)
.
toBe
(
'
But soft, what light through yonder airlock breaks?
'
);
const
first_msg
=
view
.
model
.
messages
.
findWhere
({
'
message
'
:
'
But soft, what light through yonder airlock breaks?
'
});
expect
(
textarea
.
value
).
toBe
(
''
);
view
.
onKeyDown
({
target
:
textarea
,
keyCode
:
38
// Up arrow
});
await
new
Promise
((
resolve
,
reject
)
=>
view
.
model
.
messages
.
once
(
'
rendered
'
,
resolve
));
expect
(
textarea
.
value
).
toBe
(
'
But soft, what light through yonder airlock breaks?
'
);
expect
(
view
.
model
.
messages
.
at
(
0
).
get
(
'
correcting
'
)).
toBe
(
true
);
expect
(
view
.
el
.
querySelectorAll
(
'
.chat-msg
'
).
length
).
toBe
(
1
);
expect
(
u
.
hasClass
(
'
correcting
'
,
view
.
el
.
querySelector
(
'
.chat-msg
'
))).
toBe
(
true
);
spyOn
(
_converse
.
connection
,
'
send
'
);
textarea
.
value
=
'
But soft, what light through yonder window breaks?
'
;
view
.
onKeyDown
({
target
:
textarea
,
preventDefault
:
function
preventDefault
()
{},
keyCode
:
13
// Enter
});
expect
(
_converse
.
connection
.
send
).
toHaveBeenCalled
();
await
new
Promise
((
resolve
,
reject
)
=>
view
.
model
.
messages
.
once
(
'
rendered
'
,
resolve
));
const
msg
=
_converse
.
connection
.
send
.
calls
.
all
()[
0
].
args
[
0
];
expect
(
msg
.
toLocaleString
())
.
toBe
(
`<message from="romeo@montague.lit/orchard" id="
${
msg
.
nodeTree
.
getAttribute
(
"
id
"
)}
" `
+
`to="lounge@montague.lit" type="groupchat" `
+
`xmlns="jabber:client">`
+
`<body>But soft, what light through yonder window breaks?</body>`
+
`<active xmlns="http://jabber.org/protocol/chatstates"/>`
+
`<replace id="
${
first_msg
.
get
(
"
msgid
"
)}
" xmlns="urn:xmpp:message-correct:0"/>`
+
`<origin-id id="
${
msg
.
nodeTree
.
querySelector
(
'
origin-id
'
).
getAttribute
(
"
id
"
)}
" xmlns="urn:xmpp:sid:0"/>`
+
`</message>`
);
expect
(
view
.
model
.
messages
.
models
.
length
).
toBe
(
1
);
const
corrected_message
=
view
.
model
.
messages
.
at
(
0
);
expect
(
corrected_message
.
get
(
'
msgid
'
)).
toBe
(
first_msg
.
get
(
'
msgid
'
));
expect
(
corrected_message
.
get
(
'
correcting
'
)).
toBe
(
false
);
const
older_versions
=
corrected_message
.
get
(
'
older_versions
'
);
const
keys
=
Object
.
keys
(
older_versions
);
expect
(
keys
.
length
).
toBe
(
1
);
expect
(
older_versions
[
keys
[
0
]]).
toBe
(
'
But soft, what light through yonder airlock breaks?
'
);
expect
(
view
.
el
.
querySelectorAll
(
'
.chat-msg
'
).
length
).
toBe
(
1
);
expect
(
u
.
hasClass
(
'
correcting
'
,
view
.
el
.
querySelector
(
'
.chat-msg
'
))).
toBe
(
false
);
// Check that messages from other users are skipped
await
view
.
model
.
onMessage
(
$msg
({
'
from
'
:
muc_jid
+
'
/someone-else
'
,
'
id
'
:
(
new
Date
()).
getTime
(),
'
to
'
:
'
romeo@montague.lit
'
,
'
type
'
:
'
groupchat
'
}).
c
(
'
body
'
).
t
(
'
Hello world
'
).
tree
());
await
new
Promise
((
resolve
,
reject
)
=>
view
.
once
(
'
messageInserted
'
,
resolve
));
expect
(
view
.
el
.
querySelectorAll
(
'
.chat-msg
'
).
length
).
toBe
(
2
);
// Test that pressing the down arrow cancels message correction
expect
(
textarea
.
value
).
toBe
(
''
);
view
.
onKeyDown
({
target
:
textarea
,
keyCode
:
38
// Up arrow
});
expect
(
textarea
.
value
).
toBe
(
'
But soft, what light through yonder window breaks?
'
);
expect
(
view
.
model
.
messages
.
at
(
0
).
get
(
'
correcting
'
)).
toBe
(
true
);
expect
(
view
.
el
.
querySelectorAll
(
'
.chat-msg
'
).
length
).
toBe
(
2
);
await
u
.
waitUntil
(()
=>
u
.
hasClass
(
'
correcting
'
,
view
.
el
.
querySelector
(
'
.chat-msg
'
)),
500
);
expect
(
textarea
.
value
).
toBe
(
'
But soft, what light through yonder window breaks?
'
);
view
.
onKeyDown
({
target
:
textarea
,
keyCode
:
40
// Down arrow
});
expect
(
textarea
.
value
).
toBe
(
''
);
expect
(
view
.
model
.
messages
.
at
(
0
).
get
(
'
correcting
'
)).
toBe
(
false
);
expect
(
view
.
el
.
querySelectorAll
(
'
.chat-msg
'
).
length
).
toBe
(
2
);
await
u
.
waitUntil
(()
=>
!
u
.
hasClass
(
'
correcting
'
,
view
.
el
.
querySelector
(
'
.chat-msg
'
)),
500
);
done
();
}));
it
(
"
will be shown as received upon MUC reflection
"
,
mock
.
initConverse
(
null
,
[
'
rosterGroupsFetched
'
],
{},
async
function
(
done
,
_converse
)
{
await
test_utils
.
waitForRoster
(
_converse
,
'
current
'
);
const
muc_jid
=
'
lounge@montague.lit
'
;
await
test_utils
.
openAndEnterChatRoom
(
_converse
,
muc_jid
,
'
romeo
'
);
const
view
=
_converse
.
api
.
chatviews
.
get
(
muc_jid
);
const
textarea
=
view
.
el
.
querySelector
(
'
textarea.chat-textarea
'
);
textarea
.
value
=
'
But soft, what light through yonder airlock breaks?
'
;
view
.
onKeyDown
({
target
:
textarea
,
preventDefault
:
function
preventDefault
()
{},
keyCode
:
13
// Enter
});
await
new
Promise
((
resolve
,
reject
)
=>
view
.
once
(
'
messageInserted
'
,
resolve
));
expect
(
view
.
el
.
querySelectorAll
(
'
.chat-msg__body.chat-msg__body--received
'
).
length
).
toBe
(
0
);
const
msg_obj
=
view
.
model
.
messages
.
at
(
0
);
const
stanza
=
u
.
toStanza
(
`
<message xmlns="jabber:client"
from="
${
msg_obj
.
get
(
'
from
'
)}
"
to="
${
_converse
.
connection
.
jid
}
"
type="groupchat">
<msg_body>
${
msg_obj
.
get
(
'
message
'
)}
</msg_body>
<stanza-id xmlns="urn:xmpp:sid:0"
id="5f3dbc5e-e1d3-4077-a492-693f3769c7ad"
by="lounge@montague.lit"/>
<origin-id xmlns="urn:xmpp:sid:0" id="
${
msg_obj
.
get
(
'
origin_id
'
)}
"/>
</message>`
);
await
view
.
model
.
onMessage
(
stanza
);
await
u
.
waitUntil
(()
=>
view
.
el
.
querySelectorAll
(
'
.chat-msg__body.chat-msg__body--received
'
).
length
,
500
);
expect
(
view
.
el
.
querySelectorAll
(
'
.chat-msg__receipt
'
).
length
).
toBe
(
0
);
expect
(
view
.
el
.
querySelectorAll
(
'
.chat-msg__body.chat-msg__body--received
'
).
length
).
toBe
(
1
);
expect
(
view
.
model
.
messages
.
length
).
toBe
(
1
);
const
message
=
view
.
model
.
messages
.
at
(
0
);
expect
(
message
.
get
(
'
stanza_id lounge@montague.lit
'
)).
toBe
(
'
5f3dbc5e-e1d3-4077-a492-693f3769c7ad
'
);
expect
(
message
.
get
(
'
origin_id
'
)).
toBe
(
msg_obj
.
get
(
'
origin_id
'
));
done
();
}));
it
(
"
gets updated with its stanza-id upon MUC reflection
"
,
mock
.
initConverse
(
null
,
[
'
rosterGroupsFetched
'
],
{},
async
function
(
done
,
_converse
)
{
const
muc_jid
=
'
room@muc.example.com
'
;
await
test_utils
.
openAndEnterChatRoom
(
_converse
,
muc_jid
,
'
romeo
'
);
const
view
=
_converse
.
api
.
chatviews
.
get
(
muc_jid
);
view
.
model
.
sendMessage
(
'
hello world
'
);
await
u
.
waitUntil
(()
=>
_converse
.
api
.
chats
.
get
().
length
);
await
u
.
waitUntil
(()
=>
view
.
model
.
messages
.
length
===
1
);
const
msg
=
view
.
model
.
messages
.
at
(
0
);
expect
(
msg
.
get
(
'
stanza_id
'
)).
toBeUndefined
();
expect
(
msg
.
get
(
'
origin_id
'
)).
toBe
(
msg
.
get
(
'
origin_id
'
));
const
stanza
=
u
.
toStanza
(
`
<message xmlns="jabber:client"
from="room@muc.example.com/romeo"
to="
${
_converse
.
connection
.
jid
}
"
type="groupchat">
<body>Hello world</body>
<stanza-id xmlns="urn:xmpp:sid:0"
id="5f3dbc5e-e1d3-4077-a492-693f3769c7ad"
by="room@muc.example.com"/>
<origin-id xmlns="urn:xmpp:sid:0" id="
${
msg
.
get
(
'
origin_id
'
)}
"/>
</message>`
);
spyOn
(
view
.
model
,
'
updateMessage
'
).
and
.
callThrough
();
_converse
.
connection
.
_dataRecv
(
test_utils
.
createRequest
(
stanza
));
await
u
.
waitUntil
(()
=>
view
.
model
.
updateMessage
.
calls
.
count
()
===
1
);
expect
(
view
.
model
.
messages
.
length
).
toBe
(
1
);
expect
(
view
.
model
.
messages
.
at
(
0
).
get
(
'
stanza_id room@muc.example.com
'
)).
toBe
(
"
5f3dbc5e-e1d3-4077-a492-693f3769c7ad
"
);
expect
(
view
.
model
.
messages
.
at
(
0
).
get
(
'
origin_id
'
)).
toBe
(
msg
.
get
(
'
origin_id
'
));
done
();
}));
it
(
"
can cause a delivery receipt to be returned
"
,
mock
.
initConverse
(
null
,
[
'
rosterGroupsFetched
'
],
{},
async
function
(
done
,
_converse
)
{
await
test_utils
.
waitForRoster
(
_converse
,
'
current
'
);
const
muc_jid
=
'
lounge@montague.lit
'
;
await
test_utils
.
openAndEnterChatRoom
(
_converse
,
muc_jid
,
'
romeo
'
);
const
view
=
_converse
.
api
.
chatviews
.
get
(
muc_jid
);
const
textarea
=
view
.
el
.
querySelector
(
'
textarea.chat-textarea
'
);
textarea
.
value
=
'
But soft, what light through yonder airlock breaks?
'
;
view
.
onKeyDown
({
target
:
textarea
,
preventDefault
:
function
preventDefault
()
{},
keyCode
:
13
// Enter
});
await
new
Promise
((
resolve
,
reject
)
=>
view
.
once
(
'
messageInserted
'
,
resolve
));
expect
(
view
.
el
.
querySelectorAll
(
'
.chat-msg
'
).
length
).
toBe
(
1
);
const
msg_obj
=
view
.
model
.
messages
.
at
(
0
);
const
stanza
=
u
.
toStanza
(
`
<message xml:lang="en" to="romeo@montague.lit/orchard"
from="lounge@montague.lit/some1" type="groupchat" xmlns="jabber:client">
<received xmlns="urn:xmpp:receipts" id="
${
msg_obj
.
get
(
'
msgid
'
)}
"/>
<origin-id xmlns="urn:xmpp:sid:0" id="CE08D448-5ED8-4B6A-BB5B-07ED9DFE4FF0"/>
</message>`
);
spyOn
(
_converse
.
api
,
"
trigger
"
).
and
.
callThrough
();
spyOn
(
view
.
model
,
"
isReceipt
"
).
and
.
callThrough
();
_converse
.
connection
.
_dataRecv
(
test_utils
.
createRequest
(
stanza
));
await
u
.
waitUntil
(()
=>
view
.
model
.
isReceipt
.
calls
.
count
()
===
1
);
expect
(
view
.
el
.
querySelectorAll
(
'
.chat-msg
'
).
length
).
toBe
(
1
);
expect
(
view
.
el
.
querySelectorAll
(
'
.chat-msg__receipt
'
).
length
).
toBe
(
0
);
expect
(
_converse
.
api
.
trigger
).
toHaveBeenCalledWith
(
'
message
'
,
jasmine
.
any
(
Object
));
done
();
}));
it
(
"
can cause a chat marker to be returned
"
,
mock
.
initConverse
(
null
,
[
'
rosterGroupsFetched
'
],
{},
async
function
(
done
,
_converse
)
{
await
test_utils
.
waitForRoster
(
_converse
,
'
current
'
);
const
muc_jid
=
'
lounge@montague.lit
'
;
await
test_utils
.
openAndEnterChatRoom
(
_converse
,
muc_jid
,
'
romeo
'
);
const
view
=
_converse
.
api
.
chatviews
.
get
(
muc_jid
);
const
textarea
=
view
.
el
.
querySelector
(
'
textarea.chat-textarea
'
);
textarea
.
value
=
'
But soft, what light through yonder airlock breaks?
'
;
view
.
onKeyDown
({
target
:
textarea
,
preventDefault
:
function
preventDefault
()
{},
keyCode
:
13
// Enter
});
await
new
Promise
((
resolve
,
reject
)
=>
view
.
once
(
'
messageInserted
'
,
resolve
));
expect
(
view
.
el
.
querySelectorAll
(
'
.chat-msg
'
).
length
).
toBe
(
1
);
expect
(
view
.
el
.
querySelector
(
'
.chat-msg .chat-msg__body
'
).
textContent
.
trim
())
.
toBe
(
"
But soft, what light through yonder airlock breaks?
"
);
const
msg_obj
=
view
.
model
.
messages
.
at
(
0
);
let
stanza
=
u
.
toStanza
(
`
<message xml:lang="en" to="romeo@montague.lit/orchard"
from="lounge@montague.lit/some1" type="groupchat" xmlns="jabber:client">
<received xmlns="urn:xmpp:chat-markers:0" id="
${
msg_obj
.
get
(
'
msgid
'
)}
"/>
</message>`
);
spyOn
(
view
.
model
,
"
isChatMarker
"
).
and
.
callThrough
();
_converse
.
connection
.
_dataRecv
(
test_utils
.
createRequest
(
stanza
));
await
u
.
waitUntil
(()
=>
view
.
model
.
isChatMarker
.
calls
.
count
()
===
1
);
expect
(
view
.
el
.
querySelectorAll
(
'
.chat-msg
'
).
length
).
toBe
(
1
);
expect
(
view
.
el
.
querySelectorAll
(
'
.chat-msg__receipt
'
).
length
).
toBe
(
0
);
stanza
=
u
.
toStanza
(
`
<message xml:lang="en" to="romeo@montague.lit/orchard"
from="lounge@montague.lit/some1" type="groupchat" xmlns="jabber:client">
<displayed xmlns="urn:xmpp:chat-markers:0" id="
${
msg_obj
.
get
(
'
msgid
'
)}
"/>
</message>`
);
_converse
.
connection
.
_dataRecv
(
test_utils
.
createRequest
(
stanza
));
await
u
.
waitUntil
(()
=>
view
.
model
.
isChatMarker
.
calls
.
count
()
===
2
);
expect
(
view
.
el
.
querySelectorAll
(
'
.chat-msg
'
).
length
).
toBe
(
1
);
expect
(
view
.
el
.
querySelectorAll
(
'
.chat-msg__receipt
'
).
length
).
toBe
(
0
);
stanza
=
u
.
toStanza
(
`
<message xml:lang="en" to="romeo@montague.lit/orchard"
from="lounge@montague.lit/some1" type="groupchat" xmlns="jabber:client">
<acknowledged xmlns="urn:xmpp:chat-markers:0" id="
${
msg_obj
.
get
(
'
msgid
'
)}
"/>
</message>`
);
_converse
.
connection
.
_dataRecv
(
test_utils
.
createRequest
(
stanza
));
await
u
.
waitUntil
(()
=>
view
.
model
.
isChatMarker
.
calls
.
count
()
===
3
);
expect
(
view
.
el
.
querySelectorAll
(
'
.chat-msg
'
).
length
).
toBe
(
1
);
expect
(
view
.
el
.
querySelectorAll
(
'
.chat-msg__receipt
'
).
length
).
toBe
(
0
);
stanza
=
u
.
toStanza
(
`
<message xml:lang="en" to="romeo@montague.lit/orchard"
from="lounge@montague.lit/some1" type="groupchat" xmlns="jabber:client">
<body>'tis I!</body>
<markable xmlns="urn:xmpp:chat-markers:0"/>
</message>`
);
_converse
.
connection
.
_dataRecv
(
test_utils
.
createRequest
(
stanza
));
await
u
.
waitUntil
(()
=>
view
.
model
.
isChatMarker
.
calls
.
count
()
===
4
);
expect
(
view
.
el
.
querySelectorAll
(
'
.chat-msg
'
).
length
).
toBe
(
2
);
expect
(
view
.
el
.
querySelectorAll
(
'
.chat-msg__receipt
'
).
length
).
toBe
(
0
);
done
();
}));
describe
(
"
when received
"
,
function
()
{
it
(
"
highlights all users mentioned via XEP-0372 references
"
,
mock
.
initConverse
(
null
,
[
'
rosterGroupsFetched
'
],
{},
async
function
(
done
,
_converse
)
{
const
muc_jid
=
'
lounge@montague.lit
'
;
await
test_utils
.
openAndEnterChatRoom
(
_converse
,
muc_jid
,
'
tom
'
);
const
view
=
_converse
.
api
.
chatviews
.
get
(
muc_jid
);
[
'
z3r0
'
,
'
mr.robot
'
,
'
gibson
'
,
'
sw0rdf1sh
'
].
forEach
((
nick
)
=>
{
_converse
.
connection
.
_dataRecv
(
test_utils
.
createRequest
(
$pres
({
'
to
'
:
'
tom@montague.lit/resource
'
,
'
from
'
:
`lounge@montague.lit/
${
nick
}
`
})
.
c
(
'
x
'
,
{
xmlns
:
Strophe
.
NS
.
MUC_USER
})
.
c
(
'
item
'
,
{
'
affiliation
'
:
'
none
'
,
'
jid
'
:
`
${
nick
}
@montague.lit/resource`
,
'
role
'
:
'
participant
'
}))
);
});
const
msg
=
$msg
({
from
:
'
lounge@montague.lit/gibson
'
,
id
:
(
new
Date
()).
getTime
(),
to
:
'
romeo@montague.lit
'
,
type
:
'
groupchat
'
}).
c
(
'
body
'
).
t
(
'
hello z3r0 tom mr.robot, how are you?
'
).
up
()
.
c
(
'
reference
'
,
{
'
xmlns
'
:
'
urn:xmpp:reference:0
'
,
'
begin
'
:
'
6
'
,
'
end
'
:
'
10
'
,
'
type
'
:
'
mention
'
,
'
uri
'
:
'
xmpp:z3r0@montague.lit
'
}).
up
()
.
c
(
'
reference
'
,
{
'
xmlns
'
:
'
urn:xmpp:reference:0
'
,
'
begin
'
:
'
11
'
,
'
end
'
:
'
14
'
,
'
type
'
:
'
mention
'
,
'
uri
'
:
'
xmpp:romeo@montague.lit
'
}).
up
()
.
c
(
'
reference
'
,
{
'
xmlns
'
:
'
urn:xmpp:reference:0
'
,
'
begin
'
:
'
15
'
,
'
end
'
:
'
23
'
,
'
type
'
:
'
mention
'
,
'
uri
'
:
'
xmpp:mr.robot@montague.lit
'
}).
nodeTree
;
await
view
.
model
.
onMessage
(
msg
);
await
new
Promise
((
resolve
,
reject
)
=>
view
.
once
(
'
messageInserted
'
,
resolve
));
const
messages
=
view
.
el
.
querySelectorAll
(
'
.chat-msg__text
'
);
expect
(
messages
.
length
).
toBe
(
1
);
expect
(
messages
[
0
].
classList
.
length
).
toEqual
(
1
);
expect
(
messages
[
0
].
innerHTML
).
toBe
(
'
hello <span class="mention">z3r0</span>
'
+
'
<span class="mention mention--self badge badge-info">tom</span>
'
+
'
<span class="mention">mr.robot</span>, how are you?
'
);
done
();
}));
});
describe
(
"
in which someone is mentioned
"
,
function
()
{
it
(
"
gets parsed for mentions which get turned into references
"
,
mock
.
initConverse
(
null
,
[
'
rosterGroupsFetched
'
],
{},
async
function
(
done
,
_converse
)
{
const
muc_jid
=
'
lounge@montague.lit
'
;
await
test_utils
.
openAndEnterChatRoom
(
_converse
,
muc_jid
,
'
tom
'
);
const
view
=
_converse
.
api
.
chatviews
.
get
(
muc_jid
);
[
'
z3r0
'
,
'
mr.robot
'
,
'
gibson
'
,
'
sw0rdf1sh
'
,
'
Link Mauve
'
].
forEach
((
nick
)
=>
{
_converse
.
connection
.
_dataRecv
(
test_utils
.
createRequest
(
$pres
({
'
to
'
:
'
tom@montague.lit/resource
'
,
'
from
'
:
`lounge@montague.lit/
${
nick
}
`
})
.
c
(
'
x
'
,
{
xmlns
:
Strophe
.
NS
.
MUC_USER
})
.
c
(
'
item
'
,
{
'
affiliation
'
:
'
none
'
,
'
jid
'
:
`
${
nick
.
replace
(
/
\s
/g
,
'
-
'
)}
@montague.lit/resource`
,
'
role
'
:
'
participant
'
})));
});
// Run a few unit tests for the parseTextForReferences method
let
[
text
,
references
]
=
view
.
model
.
parseTextForReferences
(
'
hello z3r0
'
)
expect
(
references
.
length
).
toBe
(
0
);
expect
(
text
).
toBe
(
'
hello z3r0
'
);
[
text
,
references
]
=
view
.
model
.
parseTextForReferences
(
'
hello @z3r0
'
)
expect
(
references
.
length
).
toBe
(
1
);
expect
(
text
).
toBe
(
'
hello z3r0
'
);
expect
(
JSON
.
stringify
(
references
))
.
toBe
(
'
[{"begin":6,"end":10,"value":"z3r0","type":"mention","uri":"xmpp:z3r0@montague.lit"}]
'
);
[
text
,
references
]
=
view
.
model
.
parseTextForReferences
(
'
hello @some1 @z3r0 @gibson @mr.robot, how are you?
'
)
expect
(
text
).
toBe
(
'
hello @some1 z3r0 gibson mr.robot, how are you?
'
);
expect
(
JSON
.
stringify
(
references
))
.
toBe
(
'
[{"begin":13,"end":17,"value":"z3r0","type":"mention","uri":"xmpp:z3r0@montague.lit"},
'
+
'
{"begin":18,"end":24,"value":"gibson","type":"mention","uri":"xmpp:gibson@montague.lit"},
'
+
'
{"begin":25,"end":33,"value":"mr.robot","type":"mention","uri":"xmpp:mr.robot@montague.lit"}]
'
);
[
text
,
references
]
=
view
.
model
.
parseTextForReferences
(
'
yo @gib
'
)
expect
(
text
).
toBe
(
'
yo @gib
'
);
expect
(
references
.
length
).
toBe
(
0
);
[
text
,
references
]
=
view
.
model
.
parseTextForReferences
(
'
yo @gibsonian
'
)
expect
(
text
).
toBe
(
'
yo @gibsonian
'
);
expect
(
references
.
length
).
toBe
(
0
);
[
text
,
references
]
=
view
.
model
.
parseTextForReferences
(
'
@gibson
'
)
expect
(
text
).
toBe
(
'
gibson
'
);
expect
(
references
.
length
).
toBe
(
1
);
expect
(
JSON
.
stringify
(
references
))
.
toBe
(
'
[{"begin":0,"end":6,"value":"gibson","type":"mention","uri":"xmpp:gibson@montague.lit"}]
'
);
[
text
,
references
]
=
view
.
model
.
parseTextForReferences
(
'
hi @Link Mauve how are you?
'
)
expect
(
text
).
toBe
(
'
hi Link Mauve how are you?
'
);
expect
(
references
.
length
).
toBe
(
1
);
expect
(
JSON
.
stringify
(
references
))
.
toBe
(
'
[{"begin":3,"end":13,"value":"Link Mauve","type":"mention","uri":"xmpp:Link-Mauve@montague.lit"}]
'
);
[
text
,
references
]
=
view
.
model
.
parseTextForReferences
(
'
https://example.org/@gibson
'
)
expect
(
text
).
toBe
(
'
https://example.org/@gibson
'
);
expect
(
references
.
length
).
toBe
(
0
);
expect
(
JSON
.
stringify
(
references
))
.
toBe
(
'
[]
'
);
[
text
,
references
]
=
view
.
model
.
parseTextForReferences
(
'
mail@gibson.com
'
)
expect
(
text
).
toBe
(
'
mail@gibson.com
'
);
expect
(
references
.
length
).
toBe
(
0
);
expect
(
JSON
.
stringify
(
references
))
.
toBe
(
'
[]
'
);
[
text
,
references
]
=
view
.
model
.
parseTextForReferences
(
'
https://linkmauve.fr@Link Mauve/ https://linkmauve.fr/@github/is_back gibson@gibson.com gibson@Link Mauve.fr
'
)
expect
(
text
).
toBe
(
'
https://linkmauve.fr@Link Mauve/ https://linkmauve.fr/@github/is_back gibson@gibson.com gibson@Link Mauve.fr
'
);
expect
(
references
.
length
).
toBe
(
0
);
expect
(
JSON
.
stringify
(
references
))
.
toBe
(
'
[]
'
);
done
();
}));
it
(
"
parses for mentions as indicated with an @ preceded by a space or at the start of the text
"
,
mock
.
initConverse
(
null
,
[
'
rosterGroupsFetched
'
],
{},
async
function
(
done
,
_converse
)
{
const
muc_jid
=
'
lounge@montague.lit
'
;
await
test_utils
.
openAndEnterChatRoom
(
_converse
,
muc_jid
,
'
tom
'
);
const
view
=
_converse
.
api
.
chatviews
.
get
(
muc_jid
);
[
'
NotAnAdress
'
,
'
darnuria
'
].
forEach
((
nick
)
=>
{
_converse
.
connection
.
_dataRecv
(
test_utils
.
createRequest
(
$pres
({
'
to
'
:
'
tom@montague.lit/resource
'
,
'
from
'
:
`lounge@montague.lit/
${
nick
}
`
})
.
c
(
'
x
'
,
{
xmlns
:
Strophe
.
NS
.
MUC_USER
})
.
c
(
'
item
'
,
{
'
affiliation
'
:
'
none
'
,
'
jid
'
:
`
${
nick
.
replace
(
/
\s
/g
,
'
-
'
)}
@montague.lit/resource`
,
'
role
'
:
'
participant
'
})));
});
// Test that we don't match @nick in email adresses.
let
[
text
,
references
]
=
view
.
model
.
parseTextForReferences
(
'
contact contact@NotAnAdress.eu
'
);
expect
(
references
.
length
).
toBe
(
0
);
expect
(
text
).
toBe
(
'
contact contact@NotAnAdress.eu
'
);
// Test that we don't match @nick in url
[
text
,
references
]
=
view
.
model
.
parseTextForReferences
(
'
nice website https://darnuria.eu/@darnuria
'
);
expect
(
references
.
length
).
toBe
(
0
);
expect
(
text
).
toBe
(
'
nice website https://darnuria.eu/@darnuria
'
);
done
();
}));
it
(
"
can get corrected and given new references
"
,
mock
.
initConverse
(
null
,
[
'
rosterGroupsFetched
'
],
{},
async
function
(
done
,
_converse
)
{
const
muc_jid
=
'
lounge@montague.lit
'
;
await
test_utils
.
openAndEnterChatRoom
(
_converse
,
muc_jid
,
'
tom
'
);
const
view
=
_converse
.
api
.
chatviews
.
get
(
muc_jid
);
[
'
z3r0
'
,
'
mr.robot
'
,
'
gibson
'
,
'
sw0rdf1sh
'
].
forEach
((
nick
)
=>
{
_converse
.
connection
.
_dataRecv
(
test_utils
.
createRequest
(
$pres
({
'
to
'
:
'
tom@montague.lit/resource
'
,
'
from
'
:
`lounge@montague.lit/
${
nick
}
`
})
.
c
(
'
x
'
,
{
xmlns
:
Strophe
.
NS
.
MUC_USER
})
.
c
(
'
item
'
,
{
'
affiliation
'
:
'
none
'
,
'
jid
'
:
`
${
nick
}
@montague.lit/resource`
,
'
role
'
:
'
participant
'
})));
});
const
textarea
=
view
.
el
.
querySelector
(
'
textarea.chat-textarea
'
);
textarea
.
value
=
'
hello @z3r0 @gibson @mr.robot, how are you?
'
const
enter_event
=
{
'
target
'
:
textarea
,
'
preventDefault
'
:
function
preventDefault
()
{},
'
stopPropagation
'
:
function
stopPropagation
()
{},
'
keyCode
'
:
13
// Enter
}
spyOn
(
_converse
.
connection
,
'
send
'
);
view
.
onKeyDown
(
enter_event
);
await
new
Promise
((
resolve
,
reject
)
=>
view
.
once
(
'
messageInserted
'
,
resolve
));
const
msg
=
_converse
.
connection
.
send
.
calls
.
all
()[
0
].
args
[
0
];
expect
(
msg
.
toLocaleString
())
.
toBe
(
`<message from="romeo@montague.lit/orchard" id="
${
msg
.
nodeTree
.
getAttribute
(
"
id
"
)}
" `
+
`to="lounge@montague.lit" type="groupchat" `
+
`xmlns="jabber:client">`
+
`<body>hello z3r0 gibson mr.robot, how are you?</body>`
+
`<active xmlns="http://jabber.org/protocol/chatstates"/>`
+
`<reference begin="6" end="10" type="mention" uri="xmpp:z3r0@montague.lit" xmlns="urn:xmpp:reference:0"/>`
+
`<reference begin="11" end="17" type="mention" uri="xmpp:gibson@montague.lit" xmlns="urn:xmpp:reference:0"/>`
+
`<reference begin="18" end="26" type="mention" uri="xmpp:mr.robot@montague.lit" xmlns="urn:xmpp:reference:0"/>`
+
`<origin-id id="
${
msg
.
nodeTree
.
querySelector
(
'
origin-id
'
).
getAttribute
(
"
id
"
)}
" xmlns="urn:xmpp:sid:0"/>`
+
`</message>`
);
const
first_msg
=
view
.
model
.
messages
.
findWhere
({
'
message
'
:
'
hello z3r0 gibson mr.robot, how are you?
'
});
const
action
=
view
.
el
.
querySelector
(
'
.chat-msg .chat-msg__action
'
);
action
.
style
.
opacity
=
1
;
action
.
click
();
expect
(
textarea
.
value
).
toBe
(
'
hello @z3r0 @gibson @mr.robot, how are you?
'
);
expect
(
view
.
model
.
messages
.
at
(
0
).
get
(
'
correcting
'
)).
toBe
(
true
);
expect
(
view
.
el
.
querySelectorAll
(
'
.chat-msg
'
).
length
).
toBe
(
1
);
await
u
.
waitUntil
(()
=>
u
.
hasClass
(
'
correcting
'
,
view
.
el
.
querySelector
(
'
.chat-msg
'
)),
500
);
textarea
.
value
=
'
hello @z3r0 @gibson @sw0rdf1sh, how are you?
'
;
view
.
onKeyDown
(
enter_event
);
await
u
.
waitUntil
(()
=>
view
.
el
.
querySelector
(
'
.chat-msg__text
'
).
textContent
===
'
hello z3r0 gibson sw0rdf1sh, how are you?
'
,
500
);
const
correction
=
_converse
.
connection
.
send
.
calls
.
all
()[
2
].
args
[
0
];
expect
(
correction
.
toLocaleString
())
.
toBe
(
`<message from="romeo@montague.lit/orchard" id="
${
correction
.
nodeTree
.
getAttribute
(
"
id
"
)}
" `
+
`to="lounge@montague.lit" type="groupchat" `
+
`xmlns="jabber:client">`
+
`<body>hello z3r0 gibson sw0rdf1sh, how are you?</body>`
+
`<active xmlns="http://jabber.org/protocol/chatstates"/>`
+
`<reference begin="6" end="10" type="mention" uri="xmpp:z3r0@montague.lit" xmlns="urn:xmpp:reference:0"/>`
+
`<reference begin="11" end="17" type="mention" uri="xmpp:gibson@montague.lit" xmlns="urn:xmpp:reference:0"/>`
+
`<reference begin="18" end="27" type="mention" uri="xmpp:sw0rdf1sh@montague.lit" xmlns="urn:xmpp:reference:0"/>`
+
`<replace id="
${
msg
.
nodeTree
.
getAttribute
(
"
id
"
)}
" xmlns="urn:xmpp:message-correct:0"/>`
+
`<origin-id id="
${
correction
.
nodeTree
.
querySelector
(
'
origin-id
'
).
getAttribute
(
"
id
"
)}
" xmlns="urn:xmpp:sid:0"/>`
+
`</message>`
);
done
();
}));
it
(
"
includes XEP-0372 references to that person
"
,
mock
.
initConverse
(
null
,
[
'
rosterGroupsFetched
'
],
{},
async
function
(
done
,
_converse
)
{
const
muc_jid
=
'
lounge@montague.lit
'
;
await
test_utils
.
openAndEnterChatRoom
(
_converse
,
muc_jid
,
'
romeo
'
);
const
view
=
_converse
.
api
.
chatviews
.
get
(
muc_jid
);
[
'
z3r0
'
,
'
mr.robot
'
,
'
gibson
'
,
'
sw0rdf1sh
'
].
forEach
((
nick
)
=>
{
_converse
.
connection
.
_dataRecv
(
test_utils
.
createRequest
(
$pres
({
'
to
'
:
'
tom@montague.lit/resource
'
,
'
from
'
:
`lounge@montague.lit/
${
nick
}
`
})
.
c
(
'
x
'
,
{
xmlns
:
Strophe
.
NS
.
MUC_USER
})
.
c
(
'
item
'
,
{
'
affiliation
'
:
'
none
'
,
'
jid
'
:
`
${
nick
}
@montague.lit/resource`
,
'
role
'
:
'
participant
'
})));
});
spyOn
(
_converse
.
connection
,
'
send
'
);
const
textarea
=
view
.
el
.
querySelector
(
'
textarea.chat-textarea
'
);
textarea
.
value
=
'
hello @z3r0 @gibson @mr.robot, how are you?
'
const
enter_event
=
{
'
target
'
:
textarea
,
'
preventDefault
'
:
function
preventDefault
()
{},
'
stopPropagation
'
:
function
stopPropagation
()
{},
'
keyCode
'
:
13
// Enter
}
view
.
onKeyDown
(
enter_event
);
const
msg
=
_converse
.
connection
.
send
.
calls
.
all
()[
0
].
args
[
0
];
expect
(
msg
.
toLocaleString
())
.
toBe
(
`<message from="romeo@montague.lit/orchard" id="
${
msg
.
nodeTree
.
getAttribute
(
"
id
"
)}
" `
+
`to="lounge@montague.lit" type="groupchat" `
+
`xmlns="jabber:client">`
+
`<body>hello z3r0 gibson mr.robot, how are you?</body>`
+
`<active xmlns="http://jabber.org/protocol/chatstates"/>`
+
`<reference begin="6" end="10" type="mention" uri="xmpp:z3r0@montague.lit" xmlns="urn:xmpp:reference:0"/>`
+
`<reference begin="11" end="17" type="mention" uri="xmpp:gibson@montague.lit" xmlns="urn:xmpp:reference:0"/>`
+
`<reference begin="18" end="26" type="mention" uri="xmpp:mr.robot@montague.lit" xmlns="urn:xmpp:reference:0"/>`
+
`<origin-id id="
${
msg
.
nodeTree
.
querySelector
(
'
origin-id
'
).
getAttribute
(
"
id
"
)}
" xmlns="urn:xmpp:sid:0"/>`
+
`</message>`
);
done
();
}));
});
});
}));
spec/muc_messages.js
0 → 100644
View file @
8b93e0f7
(
function
(
root
,
factory
)
{
define
([
"
jasmine
"
,
"
mock
"
,
"
test-utils
"
],
factory
);
}
(
this
,
function
(
jasmine
,
mock
,
test_utils
)
{
"
use strict
"
;
const
{
Promise
,
Strophe
,
$iq
,
$msg
,
$pres
,
sizzle
,
_
}
=
converse
.
env
;
const
u
=
converse
.
env
.
utils
;
describe
(
"
A Groupchat Message
"
,
function
()
{
it
(
"
is specially marked when you are mentioned in it
"
,
mock
.
initConverse
(
null
,
[
'
rosterGroupsFetched
'
,
'
chatBoxesFetched
'
],
{},
async
function
(
done
,
_converse
)
{
const
muc_jid
=
'
lounge@montague.lit
'
;
await
test_utils
.
openAndEnterChatRoom
(
_converse
,
muc_jid
,
'
romeo
'
);
const
view
=
_converse
.
api
.
chatviews
.
get
(
muc_jid
);
if
(
!
view
.
el
.
querySelectorAll
(
'
.chat-area
'
).
length
)
{
view
.
renderChatArea
();
}
const
message
=
'
romeo: Your attention is required
'
;
const
nick
=
mock
.
chatroom_names
[
0
],
msg
=
$msg
({
from
:
'
lounge@montague.lit/
'
+
nick
,
id
:
(
new
Date
()).
getTime
(),
to
:
'
romeo@montague.lit
'
,
type
:
'
groupchat
'
}).
c
(
'
body
'
).
t
(
message
).
tree
();
await
view
.
model
.
onMessage
(
msg
);
await
new
Promise
((
resolve
,
reject
)
=>
view
.
once
(
'
messageInserted
'
,
resolve
));
expect
(
u
.
hasClass
(
'
mentioned
'
,
view
.
el
.
querySelector
(
'
.chat-msg
'
))).
toBeTruthy
();
done
();
}));
it
(
"
can not be expected to have a unique id attribute
"
,
mock
.
initConverse
(
null
,
[
'
rosterGroupsFetched
'
,
'
chatBoxesFetched
'
],
{},
async
function
(
done
,
_converse
)
{
const
muc_jid
=
'
lounge@montague.lit
'
;
await
test_utils
.
openAndEnterChatRoom
(
_converse
,
muc_jid
,
'
romeo
'
);
const
view
=
_converse
.
api
.
chatviews
.
get
(
muc_jid
);
if
(
!
view
.
el
.
querySelectorAll
(
'
.chat-area
'
).
length
)
{
view
.
renderChatArea
();
}
const
id
=
u
.
getUniqueId
();
let
msg
=
$msg
({
from
:
'
lounge@montague.lit/some1
'
,
id
:
id
,
to
:
'
romeo@montague.lit
'
,
type
:
'
groupchat
'
}).
c
(
'
body
'
).
t
(
'
First message
'
).
tree
();
await
view
.
model
.
onMessage
(
msg
);
await
new
Promise
((
resolve
,
reject
)
=>
view
.
once
(
'
messageInserted
'
,
resolve
));
expect
(
view
.
el
.
querySelectorAll
(
'
.chat-msg
'
).
length
).
toBe
(
1
);
msg
=
$msg
({
from
:
'
lounge@montague.lit/some2
'
,
id
:
id
,
to
:
'
romeo@montague.lit
'
,
type
:
'
groupchat
'
}).
c
(
'
body
'
).
t
(
'
Another message
'
).
tree
();
await
view
.
model
.
onMessage
(
msg
);
await
new
Promise
((
resolve
,
reject
)
=>
view
.
once
(
'
messageInserted
'
,
resolve
));
expect
(
view
.
el
.
querySelectorAll
(
'
.chat-msg
'
).
length
).
toBe
(
2
);
done
();
}));
it
(
"
is ignored if it has the same stanza-id of an already received on
"
,
mock
.
initConverse
(
null
,
[
'
rosterGroupsFetched
'
],
{},
async
function
(
done
,
_converse
)
{
const
muc_jid
=
'
room@muc.example.com
'
;
await
test_utils
.
openAndEnterChatRoom
(
_converse
,
muc_jid
,
'
romeo
'
);
const
view
=
_converse
.
api
.
chatviews
.
get
(
muc_jid
);
spyOn
(
view
.
model
,
'
findDuplicateFromStanzaID
'
).
and
.
callThrough
();
let
stanza
=
u
.
toStanza
(
`
<message xmlns="jabber:client"
from="room@muc.example.com/some1"
to="
${
_converse
.
connection
.
jid
}
"
type="groupchat">
<body>Typical body text</body>
<stanza-id xmlns="urn:xmpp:sid:0"
id="5f3dbc5e-e1d3-4077-a492-693f3769c7ad"
by="room@muc.example.com"/>
</message>`
);
_converse
.
connection
.
_dataRecv
(
test_utils
.
createRequest
(
stanza
));
await
u
.
waitUntil
(()
=>
_converse
.
api
.
chats
.
get
().
length
);
await
u
.
waitUntil
(()
=>
view
.
model
.
messages
.
length
===
1
);
await
u
.
waitUntil
(()
=>
view
.
model
.
findDuplicateFromStanzaID
.
calls
.
count
()
===
1
);
let
result
=
await
view
.
model
.
findDuplicateFromStanzaID
.
calls
.
all
()[
0
].
returnValue
;
expect
(
result
).
toBe
(
undefined
);
stanza
=
u
.
toStanza
(
`
<message xmlns="jabber:client"
from="room@muc.example.com/some1"
to="
${
_converse
.
connection
.
jid
}
"
type="groupchat">
<body>Typical body text</body>
<stanza-id xmlns="urn:xmpp:sid:0"
id="5f3dbc5e-e1d3-4077-a492-693f3769c7ad"
by="room@muc.example.com"/>
</message>`
);
spyOn
(
view
.
model
,
'
updateMessage
'
);
_converse
.
connection
.
_dataRecv
(
test_utils
.
createRequest
(
stanza
));
await
u
.
waitUntil
(()
=>
view
.
model
.
findDuplicateFromStanzaID
.
calls
.
count
()
===
2
);
result
=
await
view
.
model
.
findDuplicateFromStanzaID
.
calls
.
all
()[
1
].
returnValue
;
expect
(
result
instanceof
_converse
.
Message
).
toBe
(
true
);
expect
(
view
.
model
.
messages
.
length
).
toBe
(
1
);
await
u
.
waitUntil
(()
=>
view
.
model
.
updateMessage
.
calls
.
count
());
done
();
}));
it
(
"
keeps track of the sender's role and affiliation
"
,
mock
.
initConverse
(
null
,
[
'
rosterGroupsFetched
'
],
{},
async
function
(
done
,
_converse
)
{
const
muc_jid
=
'
lounge@montague.lit
'
;
await
test_utils
.
openAndEnterChatRoom
(
_converse
,
muc_jid
,
'
romeo
'
);
const
view
=
_converse
.
api
.
chatviews
.
get
(
muc_jid
);
let
msg
=
$msg
({
from
:
'
lounge@montague.lit/romeo
'
,
id
:
(
new
Date
()).
getTime
(),
to
:
'
romeo@montague.lit
'
,
type
:
'
groupchat
'
}).
c
(
'
body
'
).
t
(
'
I wrote this message!
'
).
tree
();
await
view
.
model
.
onMessage
(
msg
);
await
new
Promise
((
resolve
,
reject
)
=>
view
.
once
(
'
messageInserted
'
,
resolve
));
expect
(
view
.
model
.
messages
.
last
().
occupant
.
get
(
'
affiliation
'
)).
toBe
(
'
owner
'
);
expect
(
view
.
model
.
messages
.
last
().
occupant
.
get
(
'
role
'
)).
toBe
(
'
moderator
'
);
expect
(
view
.
el
.
querySelectorAll
(
'
.chat-msg
'
).
length
).
toBe
(
1
);
expect
(
sizzle
(
'
.chat-msg
'
,
view
.
el
).
pop
().
classList
.
value
.
trim
()).
toBe
(
'
message chat-msg groupchat moderator owner
'
);
let
presence
=
$pres
({
to
:
'
romeo@montague.lit/orchard
'
,
from
:
'
lounge@montague.lit/romeo
'
,
id
:
u
.
getUniqueId
()
}).
c
(
'
x
'
).
attrs
({
xmlns
:
'
http://jabber.org/protocol/muc#user
'
})
.
c
(
'
item
'
).
attrs
({
affiliation
:
'
member
'
,
jid
:
'
romeo@montague.lit/orchard
'
,
role
:
'
participant
'
}).
up
()
.
c
(
'
status
'
).
attrs
({
code
:
'
110
'
}).
up
()
.
c
(
'
status
'
).
attrs
({
code
:
'
210
'
}).
nodeTree
;
_converse
.
connection
.
_dataRecv
(
test_utils
.
createRequest
(
presence
));
msg
=
$msg
({
from
:
'
lounge@montague.lit/romeo
'
,
id
:
(
new
Date
()).
getTime
(),
to
:
'
romeo@montague.lit
'
,
type
:
'
groupchat
'
}).
c
(
'
body
'
).
t
(
'
Another message!
'
).
tree
();
await
view
.
model
.
onMessage
(
msg
);
await
new
Promise
((
resolve
,
reject
)
=>
view
.
once
(
'
messageInserted
'
,
resolve
));
expect
(
view
.
model
.
messages
.
last
().
occupant
.
get
(
'
affiliation
'
)).
toBe
(
'
member
'
);
expect
(
view
.
model
.
messages
.
last
().
occupant
.
get
(
'
role
'
)).
toBe
(
'
participant
'
);
expect
(
view
.
el
.
querySelectorAll
(
'
.chat-msg
'
).
length
).
toBe
(
2
);
expect
(
sizzle
(
'
.chat-msg
'
,
view
.
el
).
pop
().
classList
.
value
.
trim
()).
toBe
(
'
message chat-msg groupchat participant member
'
);
presence
=
$pres
({
to
:
'
romeo@montague.lit/orchard
'
,
from
:
'
lounge@montague.lit/romeo
'
,
id
:
u
.
getUniqueId
()
}).
c
(
'
x
'
).
attrs
({
xmlns
:
'
http://jabber.org/protocol/muc#user
'
})
.
c
(
'
item
'
).
attrs
({
affiliation
:
'
owner
'
,
jid
:
'
romeo@montague.lit/orchard
'
,
role
:
'
moderator
'
}).
up
()
.
c
(
'
status
'
).
attrs
({
code
:
'
110
'
}).
up
()
.
c
(
'
status
'
).
attrs
({
code
:
'
210
'
}).
nodeTree
;
_converse
.
connection
.
_dataRecv
(
test_utils
.
createRequest
(
presence
));
view
.
model
.
sendMessage
(
'
hello world
'
);
await
u
.
waitUntil
(()
=>
view
.
el
.
querySelectorAll
(
'
.chat-msg
'
).
length
===
3
);
expect
(
view
.
model
.
messages
.
last
().
occupant
.
get
(
'
affiliation
'
)).
toBe
(
'
owner
'
);
expect
(
view
.
model
.
messages
.
last
().
occupant
.
get
(
'
role
'
)).
toBe
(
'
moderator
'
);
expect
(
view
.
el
.
querySelectorAll
(
'
.chat-msg
'
).
length
).
toBe
(
3
);
expect
(
sizzle
(
'
.chat-msg
'
,
view
.
el
).
pop
().
classList
.
value
.
trim
()).
toBe
(
'
message chat-msg groupchat moderator owner
'
);
done
();
}));
it
(
"
keeps track whether you are the sender or not
"
,
mock
.
initConverse
(
null
,
[
'
rosterGroupsFetched
'
],
{},
async
function
(
done
,
_converse
)
{
const
muc_jid
=
'
lounge@montague.lit
'
;
await
test_utils
.
openAndEnterChatRoom
(
_converse
,
muc_jid
,
'
romeo
'
);
const
view
=
_converse
.
api
.
chatviews
.
get
(
muc_jid
);
const
msg
=
$msg
({
from
:
'
lounge@montague.lit/romeo
'
,
id
:
(
new
Date
()).
getTime
(),
to
:
'
romeo@montague.lit
'
,
type
:
'
groupchat
'
}).
c
(
'
body
'
).
t
(
'
I wrote this message!
'
).
tree
();
await
view
.
model
.
onMessage
(
msg
);
await
new
Promise
((
resolve
,
reject
)
=>
view
.
once
(
'
messageInserted
'
,
resolve
));
expect
(
view
.
model
.
messages
.
last
().
get
(
'
sender
'
)).
toBe
(
'
me
'
);
done
();
}));
it
(
"
can be replaced with a correction
"
,
mock
.
initConverse
(
null
,
[
'
rosterGroupsFetched
'
],
{},
async
function
(
done
,
_converse
)
{
const
muc_jid
=
'
lounge@montague.lit
'
;
await
test_utils
.
openAndEnterChatRoom
(
_converse
,
muc_jid
,
'
romeo
'
);
const
view
=
_converse
.
api
.
chatviews
.
get
(
muc_jid
);
const
stanza
=
$pres
({
to
:
'
romeo@montague.lit/_converse.js-29092160
'
,
from
:
'
coven@chat.shakespeare.lit/newguy
'
})
.
c
(
'
x
'
,
{
xmlns
:
Strophe
.
NS
.
MUC_USER
})
.
c
(
'
item
'
,
{
'
affiliation
'
:
'
none
'
,
'
jid
'
:
'
newguy@montague.lit/_converse.js-290929789
'
,
'
role
'
:
'
participant
'
}).
tree
();
_converse
.
connection
.
_dataRecv
(
test_utils
.
createRequest
(
stanza
));
const
msg_id
=
u
.
getUniqueId
();
await
view
.
model
.
onMessage
(
$msg
({
'
from
'
:
'
lounge@montague.lit/newguy
'
,
'
to
'
:
_converse
.
connection
.
jid
,
'
type
'
:
'
groupchat
'
,
'
id
'
:
msg_id
,
}).
c
(
'
body
'
).
t
(
'
But soft, what light through yonder airlock breaks?
'
).
tree
());
await
new
Promise
((
resolve
,
reject
)
=>
view
.
once
(
'
messageInserted
'
,
resolve
));
expect
(
view
.
el
.
querySelectorAll
(
'
.chat-msg
'
).
length
).
toBe
(
1
);
expect
(
view
.
el
.
querySelector
(
'
.chat-msg__text
'
).
textContent
)
.
toBe
(
'
But soft, what light through yonder airlock breaks?
'
);
await
view
.
model
.
onMessage
(
$msg
({
'
from
'
:
'
lounge@montague.lit/newguy
'
,
'
to
'
:
_converse
.
connection
.
jid
,
'
type
'
:
'
groupchat
'
,
'
id
'
:
u
.
getUniqueId
(),
}).
c
(
'
body
'
).
t
(
'
But soft, what light through yonder chimney breaks?
'
).
up
()
.
c
(
'
replace
'
,
{
'
id
'
:
msg_id
,
'
xmlns
'
:
'
urn:xmpp:message-correct:0
'
}).
tree
());
await
u
.
waitUntil
(()
=>
view
.
el
.
querySelector
(
'
.chat-msg__text
'
).
textContent
===
'
But soft, what light through yonder chimney breaks?
'
,
500
);
expect
(
view
.
el
.
querySelectorAll
(
'
.chat-msg
'
).
length
).
toBe
(
1
);
expect
(
view
.
el
.
querySelectorAll
(
'
.chat-msg__content .fa-edit
'
).
length
).
toBe
(
1
);
await
view
.
model
.
onMessage
(
$msg
({
'
from
'
:
'
lounge@montague.lit/newguy
'
,
'
to
'
:
_converse
.
connection
.
jid
,
'
type
'
:
'
groupchat
'
,
'
id
'
:
u
.
getUniqueId
(),
}).
c
(
'
body
'
).
t
(
'
But soft, what light through yonder window breaks?
'
).
up
()
.
c
(
'
replace
'
,
{
'
id
'
:
msg_id
,
'
xmlns
'
:
'
urn:xmpp:message-correct:0
'
}).
tree
());
await
u
.
waitUntil
(()
=>
view
.
el
.
querySelector
(
'
.chat-msg__text
'
).
textContent
===
'
But soft, what light through yonder window breaks?
'
,
500
);
expect
(
view
.
el
.
querySelectorAll
(
'
.chat-msg
'
).
length
).
toBe
(
1
);
expect
(
view
.
el
.
querySelectorAll
(
'
.chat-msg__content .fa-edit
'
).
length
).
toBe
(
1
);
view
.
el
.
querySelector
(
'
.chat-msg__content .fa-edit
'
).
click
();
const
modal
=
view
.
model
.
messages
.
at
(
0
).
message_versions_modal
;
await
u
.
waitUntil
(()
=>
u
.
isVisible
(
modal
.
el
),
1000
);
const
older_msgs
=
modal
.
el
.
querySelectorAll
(
'
.older-msg
'
);
expect
(
older_msgs
.
length
).
toBe
(
2
);
expect
(
older_msgs
[
0
].
childNodes
[
1
].
textContent
).
toBe
(
'
: But soft, what light through yonder airlock breaks?
'
);
expect
(
older_msgs
[
0
].
childNodes
[
0
].
nodeName
).
toBe
(
'
TIME
'
);
expect
(
older_msgs
[
1
].
childNodes
[
0
].
nodeName
).
toBe
(
'
TIME
'
);
expect
(
older_msgs
[
1
].
childNodes
[
1
].
textContent
).
toBe
(
'
: But soft, what light through yonder chimney breaks?
'
);
done
();
}));
it
(
"
can be sent as a correction by using the up arrow
"
,
mock
.
initConverse
(
null
,
[
'
rosterGroupsFetched
'
],
{},
async
function
(
done
,
_converse
)
{
const
muc_jid
=
'
lounge@montague.lit
'
;
await
test_utils
.
openAndEnterChatRoom
(
_converse
,
muc_jid
,
'
romeo
'
);
const
view
=
_converse
.
api
.
chatviews
.
get
(
muc_jid
);
const
textarea
=
view
.
el
.
querySelector
(
'
textarea.chat-textarea
'
);
expect
(
textarea
.
value
).
toBe
(
''
);
view
.
onKeyDown
({
target
:
textarea
,
keyCode
:
38
// Up arrow
});
expect
(
textarea
.
value
).
toBe
(
''
);
textarea
.
value
=
'
But soft, what light through yonder airlock breaks?
'
;
view
.
onKeyDown
({
target
:
textarea
,
preventDefault
:
function
preventDefault
()
{},
keyCode
:
13
// Enter
});
await
new
Promise
((
resolve
,
reject
)
=>
view
.
once
(
'
messageInserted
'
,
resolve
));
expect
(
view
.
el
.
querySelectorAll
(
'
.chat-msg
'
).
length
).
toBe
(
1
);
expect
(
view
.
el
.
querySelector
(
'
.chat-msg__text
'
).
textContent
)
.
toBe
(
'
But soft, what light through yonder airlock breaks?
'
);
const
first_msg
=
view
.
model
.
messages
.
findWhere
({
'
message
'
:
'
But soft, what light through yonder airlock breaks?
'
});
expect
(
textarea
.
value
).
toBe
(
''
);
view
.
onKeyDown
({
target
:
textarea
,
keyCode
:
38
// Up arrow
});
await
new
Promise
((
resolve
,
reject
)
=>
view
.
model
.
messages
.
once
(
'
rendered
'
,
resolve
));
expect
(
textarea
.
value
).
toBe
(
'
But soft, what light through yonder airlock breaks?
'
);
expect
(
view
.
model
.
messages
.
at
(
0
).
get
(
'
correcting
'
)).
toBe
(
true
);
expect
(
view
.
el
.
querySelectorAll
(
'
.chat-msg
'
).
length
).
toBe
(
1
);
expect
(
u
.
hasClass
(
'
correcting
'
,
view
.
el
.
querySelector
(
'
.chat-msg
'
))).
toBe
(
true
);
spyOn
(
_converse
.
connection
,
'
send
'
);
textarea
.
value
=
'
But soft, what light through yonder window breaks?
'
;
view
.
onKeyDown
({
target
:
textarea
,
preventDefault
:
function
preventDefault
()
{},
keyCode
:
13
// Enter
});
expect
(
_converse
.
connection
.
send
).
toHaveBeenCalled
();
await
new
Promise
((
resolve
,
reject
)
=>
view
.
model
.
messages
.
once
(
'
rendered
'
,
resolve
));
const
msg
=
_converse
.
connection
.
send
.
calls
.
all
()[
0
].
args
[
0
];
expect
(
msg
.
toLocaleString
())
.
toBe
(
`<message from="romeo@montague.lit/orchard" id="
${
msg
.
nodeTree
.
getAttribute
(
"
id
"
)}
" `
+
`to="lounge@montague.lit" type="groupchat" `
+
`xmlns="jabber:client">`
+
`<body>But soft, what light through yonder window breaks?</body>`
+
`<active xmlns="http://jabber.org/protocol/chatstates"/>`
+
`<replace id="
${
first_msg
.
get
(
"
msgid
"
)}
" xmlns="urn:xmpp:message-correct:0"/>`
+
`<origin-id id="
${
msg
.
nodeTree
.
querySelector
(
'
origin-id
'
).
getAttribute
(
"
id
"
)}
" xmlns="urn:xmpp:sid:0"/>`
+
`</message>`
);
expect
(
view
.
model
.
messages
.
models
.
length
).
toBe
(
1
);
const
corrected_message
=
view
.
model
.
messages
.
at
(
0
);
expect
(
corrected_message
.
get
(
'
msgid
'
)).
toBe
(
first_msg
.
get
(
'
msgid
'
));
expect
(
corrected_message
.
get
(
'
correcting
'
)).
toBe
(
false
);
const
older_versions
=
corrected_message
.
get
(
'
older_versions
'
);
const
keys
=
Object
.
keys
(
older_versions
);
expect
(
keys
.
length
).
toBe
(
1
);
expect
(
older_versions
[
keys
[
0
]]).
toBe
(
'
But soft, what light through yonder airlock breaks?
'
);
expect
(
view
.
el
.
querySelectorAll
(
'
.chat-msg
'
).
length
).
toBe
(
1
);
expect
(
u
.
hasClass
(
'
correcting
'
,
view
.
el
.
querySelector
(
'
.chat-msg
'
))).
toBe
(
false
);
// Check that messages from other users are skipped
await
view
.
model
.
onMessage
(
$msg
({
'
from
'
:
muc_jid
+
'
/someone-else
'
,
'
id
'
:
(
new
Date
()).
getTime
(),
'
to
'
:
'
romeo@montague.lit
'
,
'
type
'
:
'
groupchat
'
}).
c
(
'
body
'
).
t
(
'
Hello world
'
).
tree
());
await
new
Promise
((
resolve
,
reject
)
=>
view
.
once
(
'
messageInserted
'
,
resolve
));
expect
(
view
.
el
.
querySelectorAll
(
'
.chat-msg
'
).
length
).
toBe
(
2
);
// Test that pressing the down arrow cancels message correction
expect
(
textarea
.
value
).
toBe
(
''
);
view
.
onKeyDown
({
target
:
textarea
,
keyCode
:
38
// Up arrow
});
expect
(
textarea
.
value
).
toBe
(
'
But soft, what light through yonder window breaks?
'
);
expect
(
view
.
model
.
messages
.
at
(
0
).
get
(
'
correcting
'
)).
toBe
(
true
);
expect
(
view
.
el
.
querySelectorAll
(
'
.chat-msg
'
).
length
).
toBe
(
2
);
await
u
.
waitUntil
(()
=>
u
.
hasClass
(
'
correcting
'
,
view
.
el
.
querySelector
(
'
.chat-msg
'
)),
500
);
expect
(
textarea
.
value
).
toBe
(
'
But soft, what light through yonder window breaks?
'
);
view
.
onKeyDown
({
target
:
textarea
,
keyCode
:
40
// Down arrow
});
expect
(
textarea
.
value
).
toBe
(
''
);
expect
(
view
.
model
.
messages
.
at
(
0
).
get
(
'
correcting
'
)).
toBe
(
false
);
expect
(
view
.
el
.
querySelectorAll
(
'
.chat-msg
'
).
length
).
toBe
(
2
);
await
u
.
waitUntil
(()
=>
!
u
.
hasClass
(
'
correcting
'
,
view
.
el
.
querySelector
(
'
.chat-msg
'
)),
500
);
done
();
}));
it
(
"
will be shown as received upon MUC reflection
"
,
mock
.
initConverse
(
null
,
[
'
rosterGroupsFetched
'
],
{},
async
function
(
done
,
_converse
)
{
await
test_utils
.
waitForRoster
(
_converse
,
'
current
'
);
const
muc_jid
=
'
lounge@montague.lit
'
;
await
test_utils
.
openAndEnterChatRoom
(
_converse
,
muc_jid
,
'
romeo
'
);
const
view
=
_converse
.
api
.
chatviews
.
get
(
muc_jid
);
const
textarea
=
view
.
el
.
querySelector
(
'
textarea.chat-textarea
'
);
textarea
.
value
=
'
But soft, what light through yonder airlock breaks?
'
;
view
.
onKeyDown
({
target
:
textarea
,
preventDefault
:
function
preventDefault
()
{},
keyCode
:
13
// Enter
});
await
new
Promise
((
resolve
,
reject
)
=>
view
.
once
(
'
messageInserted
'
,
resolve
));
expect
(
view
.
el
.
querySelectorAll
(
'
.chat-msg__body.chat-msg__body--received
'
).
length
).
toBe
(
0
);
const
msg_obj
=
view
.
model
.
messages
.
at
(
0
);
const
stanza
=
u
.
toStanza
(
`
<message xmlns="jabber:client"
from="
${
msg_obj
.
get
(
'
from
'
)}
"
to="
${
_converse
.
connection
.
jid
}
"
type="groupchat">
<msg_body>
${
msg_obj
.
get
(
'
message
'
)}
</msg_body>
<stanza-id xmlns="urn:xmpp:sid:0"
id="5f3dbc5e-e1d3-4077-a492-693f3769c7ad"
by="lounge@montague.lit"/>
<origin-id xmlns="urn:xmpp:sid:0" id="
${
msg_obj
.
get
(
'
origin_id
'
)}
"/>
</message>`
);
await
view
.
model
.
onMessage
(
stanza
);
await
u
.
waitUntil
(()
=>
view
.
el
.
querySelectorAll
(
'
.chat-msg__body.chat-msg__body--received
'
).
length
,
500
);
expect
(
view
.
el
.
querySelectorAll
(
'
.chat-msg__receipt
'
).
length
).
toBe
(
0
);
expect
(
view
.
el
.
querySelectorAll
(
'
.chat-msg__body.chat-msg__body--received
'
).
length
).
toBe
(
1
);
expect
(
view
.
model
.
messages
.
length
).
toBe
(
1
);
const
message
=
view
.
model
.
messages
.
at
(
0
);
expect
(
message
.
get
(
'
stanza_id lounge@montague.lit
'
)).
toBe
(
'
5f3dbc5e-e1d3-4077-a492-693f3769c7ad
'
);
expect
(
message
.
get
(
'
origin_id
'
)).
toBe
(
msg_obj
.
get
(
'
origin_id
'
));
done
();
}));
it
(
"
gets updated with its stanza-id upon MUC reflection
"
,
mock
.
initConverse
(
null
,
[
'
rosterGroupsFetched
'
],
{},
async
function
(
done
,
_converse
)
{
const
muc_jid
=
'
room@muc.example.com
'
;
await
test_utils
.
openAndEnterChatRoom
(
_converse
,
muc_jid
,
'
romeo
'
);
const
view
=
_converse
.
api
.
chatviews
.
get
(
muc_jid
);
view
.
model
.
sendMessage
(
'
hello world
'
);
await
u
.
waitUntil
(()
=>
_converse
.
api
.
chats
.
get
().
length
);
await
u
.
waitUntil
(()
=>
view
.
model
.
messages
.
length
===
1
);
const
msg
=
view
.
model
.
messages
.
at
(
0
);
expect
(
msg
.
get
(
'
stanza_id
'
)).
toBeUndefined
();
expect
(
msg
.
get
(
'
origin_id
'
)).
toBe
(
msg
.
get
(
'
origin_id
'
));
const
stanza
=
u
.
toStanza
(
`
<message xmlns="jabber:client"
from="room@muc.example.com/romeo"
to="
${
_converse
.
connection
.
jid
}
"
type="groupchat">
<body>Hello world</body>
<stanza-id xmlns="urn:xmpp:sid:0"
id="5f3dbc5e-e1d3-4077-a492-693f3769c7ad"
by="room@muc.example.com"/>
<origin-id xmlns="urn:xmpp:sid:0" id="
${
msg
.
get
(
'
origin_id
'
)}
"/>
</message>`
);
spyOn
(
view
.
model
,
'
updateMessage
'
).
and
.
callThrough
();
_converse
.
connection
.
_dataRecv
(
test_utils
.
createRequest
(
stanza
));
await
u
.
waitUntil
(()
=>
view
.
model
.
updateMessage
.
calls
.
count
()
===
1
);
expect
(
view
.
model
.
messages
.
length
).
toBe
(
1
);
expect
(
view
.
model
.
messages
.
at
(
0
).
get
(
'
stanza_id room@muc.example.com
'
)).
toBe
(
"
5f3dbc5e-e1d3-4077-a492-693f3769c7ad
"
);
expect
(
view
.
model
.
messages
.
at
(
0
).
get
(
'
origin_id
'
)).
toBe
(
msg
.
get
(
'
origin_id
'
));
done
();
}));
it
(
"
can cause a delivery receipt to be returned
"
,
mock
.
initConverse
(
null
,
[
'
rosterGroupsFetched
'
],
{},
async
function
(
done
,
_converse
)
{
await
test_utils
.
waitForRoster
(
_converse
,
'
current
'
);
const
muc_jid
=
'
lounge@montague.lit
'
;
await
test_utils
.
openAndEnterChatRoom
(
_converse
,
muc_jid
,
'
romeo
'
);
const
view
=
_converse
.
api
.
chatviews
.
get
(
muc_jid
);
const
textarea
=
view
.
el
.
querySelector
(
'
textarea.chat-textarea
'
);
textarea
.
value
=
'
But soft, what light through yonder airlock breaks?
'
;
view
.
onKeyDown
({
target
:
textarea
,
preventDefault
:
function
preventDefault
()
{},
keyCode
:
13
// Enter
});
await
new
Promise
((
resolve
,
reject
)
=>
view
.
once
(
'
messageInserted
'
,
resolve
));
expect
(
view
.
el
.
querySelectorAll
(
'
.chat-msg
'
).
length
).
toBe
(
1
);
const
msg_obj
=
view
.
model
.
messages
.
at
(
0
);
const
stanza
=
u
.
toStanza
(
`
<message xml:lang="en" to="romeo@montague.lit/orchard"
from="lounge@montague.lit/some1" type="groupchat" xmlns="jabber:client">
<received xmlns="urn:xmpp:receipts" id="
${
msg_obj
.
get
(
'
msgid
'
)}
"/>
<origin-id xmlns="urn:xmpp:sid:0" id="CE08D448-5ED8-4B6A-BB5B-07ED9DFE4FF0"/>
</message>`
);
spyOn
(
_converse
.
api
,
"
trigger
"
).
and
.
callThrough
();
spyOn
(
view
.
model
,
"
isReceipt
"
).
and
.
callThrough
();
_converse
.
connection
.
_dataRecv
(
test_utils
.
createRequest
(
stanza
));
await
u
.
waitUntil
(()
=>
view
.
model
.
isReceipt
.
calls
.
count
()
===
1
);
expect
(
view
.
el
.
querySelectorAll
(
'
.chat-msg
'
).
length
).
toBe
(
1
);
expect
(
view
.
el
.
querySelectorAll
(
'
.chat-msg__receipt
'
).
length
).
toBe
(
0
);
expect
(
_converse
.
api
.
trigger
).
toHaveBeenCalledWith
(
'
message
'
,
jasmine
.
any
(
Object
));
done
();
}));
it
(
"
can cause a chat marker to be returned
"
,
mock
.
initConverse
(
null
,
[
'
rosterGroupsFetched
'
],
{},
async
function
(
done
,
_converse
)
{
await
test_utils
.
waitForRoster
(
_converse
,
'
current
'
);
const
muc_jid
=
'
lounge@montague.lit
'
;
await
test_utils
.
openAndEnterChatRoom
(
_converse
,
muc_jid
,
'
romeo
'
);
const
view
=
_converse
.
api
.
chatviews
.
get
(
muc_jid
);
const
textarea
=
view
.
el
.
querySelector
(
'
textarea.chat-textarea
'
);
textarea
.
value
=
'
But soft, what light through yonder airlock breaks?
'
;
view
.
onKeyDown
({
target
:
textarea
,
preventDefault
:
function
preventDefault
()
{},
keyCode
:
13
// Enter
});
await
new
Promise
((
resolve
,
reject
)
=>
view
.
once
(
'
messageInserted
'
,
resolve
));
expect
(
view
.
el
.
querySelectorAll
(
'
.chat-msg
'
).
length
).
toBe
(
1
);
expect
(
view
.
el
.
querySelector
(
'
.chat-msg .chat-msg__body
'
).
textContent
.
trim
())
.
toBe
(
"
But soft, what light through yonder airlock breaks?
"
);
const
msg_obj
=
view
.
model
.
messages
.
at
(
0
);
let
stanza
=
u
.
toStanza
(
`
<message xml:lang="en" to="romeo@montague.lit/orchard"
from="lounge@montague.lit/some1" type="groupchat" xmlns="jabber:client">
<received xmlns="urn:xmpp:chat-markers:0" id="
${
msg_obj
.
get
(
'
msgid
'
)}
"/>
</message>`
);
spyOn
(
view
.
model
,
"
isChatMarker
"
).
and
.
callThrough
();
_converse
.
connection
.
_dataRecv
(
test_utils
.
createRequest
(
stanza
));
await
u
.
waitUntil
(()
=>
view
.
model
.
isChatMarker
.
calls
.
count
()
===
1
);
expect
(
view
.
el
.
querySelectorAll
(
'
.chat-msg
'
).
length
).
toBe
(
1
);
expect
(
view
.
el
.
querySelectorAll
(
'
.chat-msg__receipt
'
).
length
).
toBe
(
0
);
stanza
=
u
.
toStanza
(
`
<message xml:lang="en" to="romeo@montague.lit/orchard"
from="lounge@montague.lit/some1" type="groupchat" xmlns="jabber:client">
<displayed xmlns="urn:xmpp:chat-markers:0" id="
${
msg_obj
.
get
(
'
msgid
'
)}
"/>
</message>`
);
_converse
.
connection
.
_dataRecv
(
test_utils
.
createRequest
(
stanza
));
await
u
.
waitUntil
(()
=>
view
.
model
.
isChatMarker
.
calls
.
count
()
===
2
);
expect
(
view
.
el
.
querySelectorAll
(
'
.chat-msg
'
).
length
).
toBe
(
1
);
expect
(
view
.
el
.
querySelectorAll
(
'
.chat-msg__receipt
'
).
length
).
toBe
(
0
);
stanza
=
u
.
toStanza
(
`
<message xml:lang="en" to="romeo@montague.lit/orchard"
from="lounge@montague.lit/some1" type="groupchat" xmlns="jabber:client">
<acknowledged xmlns="urn:xmpp:chat-markers:0" id="
${
msg_obj
.
get
(
'
msgid
'
)}
"/>
</message>`
);
_converse
.
connection
.
_dataRecv
(
test_utils
.
createRequest
(
stanza
));
await
u
.
waitUntil
(()
=>
view
.
model
.
isChatMarker
.
calls
.
count
()
===
3
);
expect
(
view
.
el
.
querySelectorAll
(
'
.chat-msg
'
).
length
).
toBe
(
1
);
expect
(
view
.
el
.
querySelectorAll
(
'
.chat-msg__receipt
'
).
length
).
toBe
(
0
);
stanza
=
u
.
toStanza
(
`
<message xml:lang="en" to="romeo@montague.lit/orchard"
from="lounge@montague.lit/some1" type="groupchat" xmlns="jabber:client">
<body>'tis I!</body>
<markable xmlns="urn:xmpp:chat-markers:0"/>
</message>`
);
_converse
.
connection
.
_dataRecv
(
test_utils
.
createRequest
(
stanza
));
await
u
.
waitUntil
(()
=>
view
.
model
.
isChatMarker
.
calls
.
count
()
===
4
);
expect
(
view
.
el
.
querySelectorAll
(
'
.chat-msg
'
).
length
).
toBe
(
2
);
expect
(
view
.
el
.
querySelectorAll
(
'
.chat-msg__receipt
'
).
length
).
toBe
(
0
);
done
();
}));
describe
(
"
when received
"
,
function
()
{
it
(
"
highlights all users mentioned via XEP-0372 references
"
,
mock
.
initConverse
(
null
,
[
'
rosterGroupsFetched
'
],
{},
async
function
(
done
,
_converse
)
{
const
muc_jid
=
'
lounge@montague.lit
'
;
await
test_utils
.
openAndEnterChatRoom
(
_converse
,
muc_jid
,
'
tom
'
);
const
view
=
_converse
.
api
.
chatviews
.
get
(
muc_jid
);
[
'
z3r0
'
,
'
mr.robot
'
,
'
gibson
'
,
'
sw0rdf1sh
'
].
forEach
((
nick
)
=>
{
_converse
.
connection
.
_dataRecv
(
test_utils
.
createRequest
(
$pres
({
'
to
'
:
'
tom@montague.lit/resource
'
,
'
from
'
:
`lounge@montague.lit/
${
nick
}
`
})
.
c
(
'
x
'
,
{
xmlns
:
Strophe
.
NS
.
MUC_USER
})
.
c
(
'
item
'
,
{
'
affiliation
'
:
'
none
'
,
'
jid
'
:
`
${
nick
}
@montague.lit/resource`
,
'
role
'
:
'
participant
'
}))
);
});
const
msg
=
$msg
({
from
:
'
lounge@montague.lit/gibson
'
,
id
:
(
new
Date
()).
getTime
(),
to
:
'
romeo@montague.lit
'
,
type
:
'
groupchat
'
}).
c
(
'
body
'
).
t
(
'
hello z3r0 tom mr.robot, how are you?
'
).
up
()
.
c
(
'
reference
'
,
{
'
xmlns
'
:
'
urn:xmpp:reference:0
'
,
'
begin
'
:
'
6
'
,
'
end
'
:
'
10
'
,
'
type
'
:
'
mention
'
,
'
uri
'
:
'
xmpp:z3r0@montague.lit
'
}).
up
()
.
c
(
'
reference
'
,
{
'
xmlns
'
:
'
urn:xmpp:reference:0
'
,
'
begin
'
:
'
11
'
,
'
end
'
:
'
14
'
,
'
type
'
:
'
mention
'
,
'
uri
'
:
'
xmpp:romeo@montague.lit
'
}).
up
()
.
c
(
'
reference
'
,
{
'
xmlns
'
:
'
urn:xmpp:reference:0
'
,
'
begin
'
:
'
15
'
,
'
end
'
:
'
23
'
,
'
type
'
:
'
mention
'
,
'
uri
'
:
'
xmpp:mr.robot@montague.lit
'
}).
nodeTree
;
await
view
.
model
.
onMessage
(
msg
);
await
new
Promise
((
resolve
,
reject
)
=>
view
.
once
(
'
messageInserted
'
,
resolve
));
const
messages
=
view
.
el
.
querySelectorAll
(
'
.chat-msg__text
'
);
expect
(
messages
.
length
).
toBe
(
1
);
expect
(
messages
[
0
].
classList
.
length
).
toEqual
(
1
);
expect
(
messages
[
0
].
innerHTML
).
toBe
(
'
hello <span class="mention">z3r0</span>
'
+
'
<span class="mention mention--self badge badge-info">tom</span>
'
+
'
<span class="mention">mr.robot</span>, how are you?
'
);
done
();
}));
});
describe
(
"
in which someone is mentioned
"
,
function
()
{
it
(
"
gets parsed for mentions which get turned into references
"
,
mock
.
initConverse
(
null
,
[
'
rosterGroupsFetched
'
],
{},
async
function
(
done
,
_converse
)
{
const
muc_jid
=
'
lounge@montague.lit
'
;
await
test_utils
.
openAndEnterChatRoom
(
_converse
,
muc_jid
,
'
tom
'
);
const
view
=
_converse
.
api
.
chatviews
.
get
(
muc_jid
);
[
'
z3r0
'
,
'
mr.robot
'
,
'
gibson
'
,
'
sw0rdf1sh
'
,
'
Link Mauve
'
].
forEach
((
nick
)
=>
{
_converse
.
connection
.
_dataRecv
(
test_utils
.
createRequest
(
$pres
({
'
to
'
:
'
tom@montague.lit/resource
'
,
'
from
'
:
`lounge@montague.lit/
${
nick
}
`
})
.
c
(
'
x
'
,
{
xmlns
:
Strophe
.
NS
.
MUC_USER
})
.
c
(
'
item
'
,
{
'
affiliation
'
:
'
none
'
,
'
jid
'
:
`
${
nick
.
replace
(
/
\s
/g
,
'
-
'
)}
@montague.lit/resource`
,
'
role
'
:
'
participant
'
})));
});
// Run a few unit tests for the parseTextForReferences method
let
[
text
,
references
]
=
view
.
model
.
parseTextForReferences
(
'
hello z3r0
'
)
expect
(
references
.
length
).
toBe
(
0
);
expect
(
text
).
toBe
(
'
hello z3r0
'
);
[
text
,
references
]
=
view
.
model
.
parseTextForReferences
(
'
hello @z3r0
'
)
expect
(
references
.
length
).
toBe
(
1
);
expect
(
text
).
toBe
(
'
hello z3r0
'
);
expect
(
JSON
.
stringify
(
references
))
.
toBe
(
'
[{"begin":6,"end":10,"value":"z3r0","type":"mention","uri":"xmpp:z3r0@montague.lit"}]
'
);
[
text
,
references
]
=
view
.
model
.
parseTextForReferences
(
'
hello @some1 @z3r0 @gibson @mr.robot, how are you?
'
)
expect
(
text
).
toBe
(
'
hello @some1 z3r0 gibson mr.robot, how are you?
'
);
expect
(
JSON
.
stringify
(
references
))
.
toBe
(
'
[{"begin":13,"end":17,"value":"z3r0","type":"mention","uri":"xmpp:z3r0@montague.lit"},
'
+
'
{"begin":18,"end":24,"value":"gibson","type":"mention","uri":"xmpp:gibson@montague.lit"},
'
+
'
{"begin":25,"end":33,"value":"mr.robot","type":"mention","uri":"xmpp:mr.robot@montague.lit"}]
'
);
[
text
,
references
]
=
view
.
model
.
parseTextForReferences
(
'
yo @gib
'
)
expect
(
text
).
toBe
(
'
yo @gib
'
);
expect
(
references
.
length
).
toBe
(
0
);
[
text
,
references
]
=
view
.
model
.
parseTextForReferences
(
'
yo @gibsonian
'
)
expect
(
text
).
toBe
(
'
yo @gibsonian
'
);
expect
(
references
.
length
).
toBe
(
0
);
[
text
,
references
]
=
view
.
model
.
parseTextForReferences
(
'
@gibson
'
)
expect
(
text
).
toBe
(
'
gibson
'
);
expect
(
references
.
length
).
toBe
(
1
);
expect
(
JSON
.
stringify
(
references
))
.
toBe
(
'
[{"begin":0,"end":6,"value":"gibson","type":"mention","uri":"xmpp:gibson@montague.lit"}]
'
);
[
text
,
references
]
=
view
.
model
.
parseTextForReferences
(
'
hi @Link Mauve how are you?
'
)
expect
(
text
).
toBe
(
'
hi Link Mauve how are you?
'
);
expect
(
references
.
length
).
toBe
(
1
);
expect
(
JSON
.
stringify
(
references
))
.
toBe
(
'
[{"begin":3,"end":13,"value":"Link Mauve","type":"mention","uri":"xmpp:Link-Mauve@montague.lit"}]
'
);
[
text
,
references
]
=
view
.
model
.
parseTextForReferences
(
'
https://example.org/@gibson
'
)
expect
(
text
).
toBe
(
'
https://example.org/@gibson
'
);
expect
(
references
.
length
).
toBe
(
0
);
expect
(
JSON
.
stringify
(
references
))
.
toBe
(
'
[]
'
);
[
text
,
references
]
=
view
.
model
.
parseTextForReferences
(
'
mail@gibson.com
'
)
expect
(
text
).
toBe
(
'
mail@gibson.com
'
);
expect
(
references
.
length
).
toBe
(
0
);
expect
(
JSON
.
stringify
(
references
))
.
toBe
(
'
[]
'
);
[
text
,
references
]
=
view
.
model
.
parseTextForReferences
(
'
https://linkmauve.fr@Link Mauve/ https://linkmauve.fr/@github/is_back gibson@gibson.com gibson@Link Mauve.fr
'
)
expect
(
text
).
toBe
(
'
https://linkmauve.fr@Link Mauve/ https://linkmauve.fr/@github/is_back gibson@gibson.com gibson@Link Mauve.fr
'
);
expect
(
references
.
length
).
toBe
(
0
);
expect
(
JSON
.
stringify
(
references
))
.
toBe
(
'
[]
'
);
done
();
}));
it
(
"
parses for mentions as indicated with an @ preceded by a space or at the start of the text
"
,
mock
.
initConverse
(
null
,
[
'
rosterGroupsFetched
'
],
{},
async
function
(
done
,
_converse
)
{
const
muc_jid
=
'
lounge@montague.lit
'
;
await
test_utils
.
openAndEnterChatRoom
(
_converse
,
muc_jid
,
'
tom
'
);
const
view
=
_converse
.
api
.
chatviews
.
get
(
muc_jid
);
[
'
NotAnAdress
'
,
'
darnuria
'
].
forEach
((
nick
)
=>
{
_converse
.
connection
.
_dataRecv
(
test_utils
.
createRequest
(
$pres
({
'
to
'
:
'
tom@montague.lit/resource
'
,
'
from
'
:
`lounge@montague.lit/
${
nick
}
`
})
.
c
(
'
x
'
,
{
xmlns
:
Strophe
.
NS
.
MUC_USER
})
.
c
(
'
item
'
,
{
'
affiliation
'
:
'
none
'
,
'
jid
'
:
`
${
nick
.
replace
(
/
\s
/g
,
'
-
'
)}
@montague.lit/resource`
,
'
role
'
:
'
participant
'
})));
});
// Test that we don't match @nick in email adresses.
let
[
text
,
references
]
=
view
.
model
.
parseTextForReferences
(
'
contact contact@NotAnAdress.eu
'
);
expect
(
references
.
length
).
toBe
(
0
);
expect
(
text
).
toBe
(
'
contact contact@NotAnAdress.eu
'
);
// Test that we don't match @nick in url
[
text
,
references
]
=
view
.
model
.
parseTextForReferences
(
'
nice website https://darnuria.eu/@darnuria
'
);
expect
(
references
.
length
).
toBe
(
0
);
expect
(
text
).
toBe
(
'
nice website https://darnuria.eu/@darnuria
'
);
done
();
}));
it
(
"
can get corrected and given new references
"
,
mock
.
initConverse
(
null
,
[
'
rosterGroupsFetched
'
],
{},
async
function
(
done
,
_converse
)
{
const
muc_jid
=
'
lounge@montague.lit
'
;
await
test_utils
.
openAndEnterChatRoom
(
_converse
,
muc_jid
,
'
tom
'
);
const
view
=
_converse
.
api
.
chatviews
.
get
(
muc_jid
);
[
'
z3r0
'
,
'
mr.robot
'
,
'
gibson
'
,
'
sw0rdf1sh
'
].
forEach
((
nick
)
=>
{
_converse
.
connection
.
_dataRecv
(
test_utils
.
createRequest
(
$pres
({
'
to
'
:
'
tom@montague.lit/resource
'
,
'
from
'
:
`lounge@montague.lit/
${
nick
}
`
})
.
c
(
'
x
'
,
{
xmlns
:
Strophe
.
NS
.
MUC_USER
})
.
c
(
'
item
'
,
{
'
affiliation
'
:
'
none
'
,
'
jid
'
:
`
${
nick
}
@montague.lit/resource`
,
'
role
'
:
'
participant
'
})));
});
const
textarea
=
view
.
el
.
querySelector
(
'
textarea.chat-textarea
'
);
textarea
.
value
=
'
hello @z3r0 @gibson @mr.robot, how are you?
'
const
enter_event
=
{
'
target
'
:
textarea
,
'
preventDefault
'
:
function
preventDefault
()
{},
'
stopPropagation
'
:
function
stopPropagation
()
{},
'
keyCode
'
:
13
// Enter
}
spyOn
(
_converse
.
connection
,
'
send
'
);
view
.
onKeyDown
(
enter_event
);
await
new
Promise
((
resolve
,
reject
)
=>
view
.
once
(
'
messageInserted
'
,
resolve
));
const
msg
=
_converse
.
connection
.
send
.
calls
.
all
()[
0
].
args
[
0
];
expect
(
msg
.
toLocaleString
())
.
toBe
(
`<message from="romeo@montague.lit/orchard" id="
${
msg
.
nodeTree
.
getAttribute
(
"
id
"
)}
" `
+
`to="lounge@montague.lit" type="groupchat" `
+
`xmlns="jabber:client">`
+
`<body>hello z3r0 gibson mr.robot, how are you?</body>`
+
`<active xmlns="http://jabber.org/protocol/chatstates"/>`
+
`<reference begin="6" end="10" type="mention" uri="xmpp:z3r0@montague.lit" xmlns="urn:xmpp:reference:0"/>`
+
`<reference begin="11" end="17" type="mention" uri="xmpp:gibson@montague.lit" xmlns="urn:xmpp:reference:0"/>`
+
`<reference begin="18" end="26" type="mention" uri="xmpp:mr.robot@montague.lit" xmlns="urn:xmpp:reference:0"/>`
+
`<origin-id id="
${
msg
.
nodeTree
.
querySelector
(
'
origin-id
'
).
getAttribute
(
"
id
"
)}
" xmlns="urn:xmpp:sid:0"/>`
+
`</message>`
);
const
first_msg
=
view
.
model
.
messages
.
findWhere
({
'
message
'
:
'
hello z3r0 gibson mr.robot, how are you?
'
});
const
action
=
view
.
el
.
querySelector
(
'
.chat-msg .chat-msg__action
'
);
action
.
style
.
opacity
=
1
;
action
.
click
();
expect
(
textarea
.
value
).
toBe
(
'
hello @z3r0 @gibson @mr.robot, how are you?
'
);
expect
(
view
.
model
.
messages
.
at
(
0
).
get
(
'
correcting
'
)).
toBe
(
true
);
expect
(
view
.
el
.
querySelectorAll
(
'
.chat-msg
'
).
length
).
toBe
(
1
);
await
u
.
waitUntil
(()
=>
u
.
hasClass
(
'
correcting
'
,
view
.
el
.
querySelector
(
'
.chat-msg
'
)),
500
);
textarea
.
value
=
'
hello @z3r0 @gibson @sw0rdf1sh, how are you?
'
;
view
.
onKeyDown
(
enter_event
);
await
u
.
waitUntil
(()
=>
view
.
el
.
querySelector
(
'
.chat-msg__text
'
).
textContent
===
'
hello z3r0 gibson sw0rdf1sh, how are you?
'
,
500
);
const
correction
=
_converse
.
connection
.
send
.
calls
.
all
()[
2
].
args
[
0
];
expect
(
correction
.
toLocaleString
())
.
toBe
(
`<message from="romeo@montague.lit/orchard" id="
${
correction
.
nodeTree
.
getAttribute
(
"
id
"
)}
" `
+
`to="lounge@montague.lit" type="groupchat" `
+
`xmlns="jabber:client">`
+
`<body>hello z3r0 gibson sw0rdf1sh, how are you?</body>`
+
`<active xmlns="http://jabber.org/protocol/chatstates"/>`
+
`<reference begin="6" end="10" type="mention" uri="xmpp:z3r0@montague.lit" xmlns="urn:xmpp:reference:0"/>`
+
`<reference begin="11" end="17" type="mention" uri="xmpp:gibson@montague.lit" xmlns="urn:xmpp:reference:0"/>`
+
`<reference begin="18" end="27" type="mention" uri="xmpp:sw0rdf1sh@montague.lit" xmlns="urn:xmpp:reference:0"/>`
+
`<replace id="
${
msg
.
nodeTree
.
getAttribute
(
"
id
"
)}
" xmlns="urn:xmpp:message-correct:0"/>`
+
`<origin-id id="
${
correction
.
nodeTree
.
querySelector
(
'
origin-id
'
).
getAttribute
(
"
id
"
)}
" xmlns="urn:xmpp:sid:0"/>`
+
`</message>`
);
done
();
}));
it
(
"
includes XEP-0372 references to that person
"
,
mock
.
initConverse
(
null
,
[
'
rosterGroupsFetched
'
],
{},
async
function
(
done
,
_converse
)
{
const
muc_jid
=
'
lounge@montague.lit
'
;
await
test_utils
.
openAndEnterChatRoom
(
_converse
,
muc_jid
,
'
romeo
'
);
const
view
=
_converse
.
api
.
chatviews
.
get
(
muc_jid
);
[
'
z3r0
'
,
'
mr.robot
'
,
'
gibson
'
,
'
sw0rdf1sh
'
].
forEach
((
nick
)
=>
{
_converse
.
connection
.
_dataRecv
(
test_utils
.
createRequest
(
$pres
({
'
to
'
:
'
tom@montague.lit/resource
'
,
'
from
'
:
`lounge@montague.lit/
${
nick
}
`
})
.
c
(
'
x
'
,
{
xmlns
:
Strophe
.
NS
.
MUC_USER
})
.
c
(
'
item
'
,
{
'
affiliation
'
:
'
none
'
,
'
jid
'
:
`
${
nick
}
@montague.lit/resource`
,
'
role
'
:
'
participant
'
})));
});
spyOn
(
_converse
.
connection
,
'
send
'
);
const
textarea
=
view
.
el
.
querySelector
(
'
textarea.chat-textarea
'
);
textarea
.
value
=
'
hello @z3r0 @gibson @mr.robot, how are you?
'
const
enter_event
=
{
'
target
'
:
textarea
,
'
preventDefault
'
:
function
preventDefault
()
{},
'
stopPropagation
'
:
function
stopPropagation
()
{},
'
keyCode
'
:
13
// Enter
}
view
.
onKeyDown
(
enter_event
);
const
msg
=
_converse
.
connection
.
send
.
calls
.
all
()[
0
].
args
[
0
];
expect
(
msg
.
toLocaleString
())
.
toBe
(
`<message from="romeo@montague.lit/orchard" id="
${
msg
.
nodeTree
.
getAttribute
(
"
id
"
)}
" `
+
`to="lounge@montague.lit" type="groupchat" `
+
`xmlns="jabber:client">`
+
`<body>hello z3r0 gibson mr.robot, how are you?</body>`
+
`<active xmlns="http://jabber.org/protocol/chatstates"/>`
+
`<reference begin="6" end="10" type="mention" uri="xmpp:z3r0@montague.lit" xmlns="urn:xmpp:reference:0"/>`
+
`<reference begin="11" end="17" type="mention" uri="xmpp:gibson@montague.lit" xmlns="urn:xmpp:reference:0"/>`
+
`<reference begin="18" end="26" type="mention" uri="xmpp:mr.robot@montague.lit" xmlns="urn:xmpp:reference:0"/>`
+
`<origin-id id="
${
msg
.
nodeTree
.
querySelector
(
'
origin-id
'
).
getAttribute
(
"
id
"
)}
" xmlns="urn:xmpp:sid:0"/>`
+
`</message>`
);
done
();
}));
});
});
}));
tests/runner.js
View file @
8b93e0f7
...
...
@@ -54,6 +54,7 @@ var specs = [
"
spec/chatbox
"
,
"
spec/user-details-modal
"
,
"
spec/messages
"
,
"
spec/muc_messages
"
,
"
spec/muc
"
,
"
spec/modtools
"
,
"
spec/room_registration
"
,
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment