more testing for connect components (#1046)
* adding more tests - covers article.jsx and elements created from its props and state - added png as static file that needs stubbing * video + channelDetails test coverage * chat + channels tests * channels cc refactor * yarn install * update snapshot and string spacing * chat.jsx test mostly tests rendering elements - does not test imported components, as those are already tested separately - does not imported functions from actions or utils as those will be tested separately as well * cleaning up - mocked response with flush promises for state/component to reflect appropriate changes * snapshot updates
This commit is contained in:
parent
dded7dc343
commit
faf1c6719b
23 changed files with 2452 additions and 337 deletions
42
app/javascript/chat/__mocks__/algoliasearchUsers.js
Normal file
42
app/javascript/chat/__mocks__/algoliasearchUsers.js
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
global.document.head.innerHTML =
|
||||
"<meta name='algolia-public-id' content='abc123' />" +
|
||||
"<meta name='algolia-public-key' content='abc123' />" +
|
||||
"<meta name='environment' content='test' />";
|
||||
|
||||
const mockIndex = {
|
||||
search: query =>
|
||||
new Promise(resolve => {
|
||||
process.nextTick(() => {
|
||||
const searchResults = {
|
||||
ma: {
|
||||
hits: [
|
||||
{
|
||||
name: 'mat',
|
||||
path: 'some_path',
|
||||
title: 'some_title',
|
||||
id: 'some_id',
|
||||
},
|
||||
],
|
||||
nbHits: 1,
|
||||
page: 0,
|
||||
nbPages: 1,
|
||||
hitsPerPage: 10,
|
||||
processingTimeMS: 1,
|
||||
exhaustiveNbHits: true,
|
||||
query: 'ma',
|
||||
params:
|
||||
'query=ma&hitsPerPage=10&filters=supported%3Atrue&restrictIndices=searchables_development%2CTag_development%2Cordered_articles_development%2Cordered_articles_by_published_at_development%2Cordered_articles_by_positive_reactions_count_development%2Cordered_comments_development',
|
||||
},
|
||||
};
|
||||
|
||||
const results = searchResults[query] || { hits: [] };
|
||||
|
||||
resolve(results);
|
||||
});
|
||||
}),
|
||||
};
|
||||
const client = {
|
||||
initIndex: index => mockIndex, // eslint-ignore-line
|
||||
};
|
||||
|
||||
export default jest.fn().mockImplementation((id, key) => client); // eslint-ignore-line
|
||||
|
|
@ -1,17 +1,17 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`<Alert /> should render and test snapshot 1`] = `
|
||||
<div
|
||||
class="chatalert__default "
|
||||
>
|
||||
More new messages below
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`<Alert /> should render and test snapshot with hidden class 1`] = `
|
||||
exports[`<Alert /> with hidden class should render and test snapshot 1`] = `
|
||||
<div
|
||||
class="chatalert__default chatalert__default--hidden"
|
||||
>
|
||||
More new messages below
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`<Alert /> without hidden class should render and test snapshot 1`] = `
|
||||
<div
|
||||
class="chatalert__default "
|
||||
>
|
||||
More new messages below
|
||||
</div>
|
||||
`;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,111 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`<Article /> should load article 1`] = `
|
||||
<div
|
||||
class="activechatchannel__activeArticle"
|
||||
>
|
||||
<div
|
||||
class="activechatchannel__activeArticleDetails"
|
||||
>
|
||||
<a
|
||||
href="/princesscarolyn/your-approval-means-nothing-to-me-42640"
|
||||
target="_blank"
|
||||
>
|
||||
<span
|
||||
class="activechatchannel__activeArticleDetailsPath"
|
||||
>
|
||||
/princesscarolyn/your-approval-means-nothing-to-me-42640
|
||||
</span>
|
||||
<img
|
||||
src=""
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
<div
|
||||
class="container"
|
||||
>
|
||||
<header>
|
||||
<div
|
||||
class="image image-final"
|
||||
style={
|
||||
Object {
|
||||
"backgroundImage": "url(princess_carolyn_is_perfect.png",
|
||||
}
|
||||
}
|
||||
/>
|
||||
</header>
|
||||
<div
|
||||
class="title"
|
||||
>
|
||||
<h1>
|
||||
Your Approval Means Nothing to Me
|
||||
</h1>
|
||||
<h3>
|
||||
<a
|
||||
class="author"
|
||||
data-content="/users/00001"
|
||||
href="/princesscarolyn"
|
||||
>
|
||||
<img
|
||||
alt="princesscarolyn"
|
||||
class="profile-pic"
|
||||
src="/princesscarolyn.png"
|
||||
/>
|
||||
<span>
|
||||
Princess Carolyn
|
||||
</span>
|
||||
<span
|
||||
class="published-at"
|
||||
>
|
||||
| July 30, 2014
|
||||
</span>
|
||||
</a>
|
||||
</h3>
|
||||
</div>
|
||||
<div
|
||||
class="body"
|
||||
>
|
||||
<div
|
||||
dangerouslySetInnerHTML={
|
||||
Object {
|
||||
"__html": "That woman can knock a drink back like a Kennedy at a wake for another Kennedy, but I'll be damned if she doesn't get s*** done!",
|
||||
}
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="activechatchannel__activeArticleActions"
|
||||
>
|
||||
<button
|
||||
class="heart-reaction-button "
|
||||
data-category="like"
|
||||
onClick={[Function]}
|
||||
>
|
||||
<img
|
||||
src=""
|
||||
/>
|
||||
</button>
|
||||
<button
|
||||
class="unicorn-reaction-button "
|
||||
data-category="unicorn"
|
||||
onClick={[Function]}
|
||||
>
|
||||
<img
|
||||
data-category="unicorn"
|
||||
src=""
|
||||
/>
|
||||
</button>
|
||||
<button
|
||||
class="readinglist-reaction-button "
|
||||
data-category="readinglist"
|
||||
onClick={[Function]}
|
||||
>
|
||||
<img
|
||||
data-category="readinglist"
|
||||
src=""
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
|
@ -0,0 +1,340 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`<ChannelDetails /> as a moderator should render and test snapshot 1`] = `
|
||||
<div
|
||||
class="channeldetails"
|
||||
>
|
||||
<h1
|
||||
class="channeldetails__name"
|
||||
>
|
||||
channel name
|
||||
</h1>
|
||||
<div
|
||||
class="channeldetails__description"
|
||||
style={
|
||||
Object {
|
||||
"marginBottom": "20px",
|
||||
}
|
||||
}
|
||||
>
|
||||
<em>
|
||||
something about this channel
|
||||
</em>
|
||||
</div>
|
||||
<div
|
||||
class="channeldetails__user"
|
||||
>
|
||||
<a
|
||||
data-content="users/by_username?url=channeluser1"
|
||||
href="/channeluser1"
|
||||
style={
|
||||
Object {
|
||||
"color": undefined,
|
||||
"padding": "3px 0px",
|
||||
}
|
||||
}
|
||||
>
|
||||
channel user 1
|
||||
</a>
|
||||
</div>
|
||||
<div
|
||||
class="channeldetails__user"
|
||||
>
|
||||
<a
|
||||
data-content="users/by_username?url=channeluser2"
|
||||
href="/channeluser2"
|
||||
style={
|
||||
Object {
|
||||
"color": undefined,
|
||||
"padding": "3px 0px",
|
||||
}
|
||||
}
|
||||
>
|
||||
channel user 2
|
||||
</a>
|
||||
</div>
|
||||
<div
|
||||
class="channeldetails__inviteusers"
|
||||
>
|
||||
<h2>
|
||||
Invite Members
|
||||
</h2>
|
||||
<input
|
||||
onKeyUp={[Function]}
|
||||
placeholder="Find users"
|
||||
/>
|
||||
<h2>
|
||||
Pending Invites:
|
||||
</h2>
|
||||
<div
|
||||
class="channeldetails__pendingusers"
|
||||
>
|
||||
<a
|
||||
data-content="users/pendingid1"
|
||||
href="/pendinguser1"
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
@pendinguser1 - pending user 1
|
||||
</a>
|
||||
</div>
|
||||
<div
|
||||
class="channeldetails__pendingusers"
|
||||
>
|
||||
<a
|
||||
data-content="users/pendingid2"
|
||||
href="/pendinguser2"
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
@pendinguser2 - pending user 2
|
||||
</a>
|
||||
</div>
|
||||
<div
|
||||
style={
|
||||
Object {
|
||||
"marginTop": "10px",
|
||||
}
|
||||
}
|
||||
>
|
||||
All functionality is early beta. Contact us if you need help with anything.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`<ChannelDetails /> as a moderator should search users and populate searched users div 1`] = `
|
||||
preact-render-spy (1 nodes)
|
||||
-------
|
||||
<div class="channeldetails">
|
||||
<h1 class="channeldetails__name">channel name</h1>
|
||||
<div
|
||||
class="channeldetails__description"
|
||||
style="margin-bottom: 20px;"
|
||||
>
|
||||
<em>something about this channel</em>
|
||||
</div>
|
||||
<div class="channeldetails__user">
|
||||
<a
|
||||
href="/channeluser1"
|
||||
style="padding: 3px 0px;"
|
||||
data-content="users/by_username?url=channeluser1"
|
||||
>
|
||||
channel user 1
|
||||
</a>
|
||||
</div>
|
||||
<div class="channeldetails__user">
|
||||
<a
|
||||
href="/channeluser2"
|
||||
style="padding: 3px 0px;"
|
||||
data-content="users/by_username?url=channeluser2"
|
||||
>
|
||||
channel user 2
|
||||
</a>
|
||||
</div>
|
||||
<div class="channeldetails__inviteusers">
|
||||
<h2>Invite Members</h2>
|
||||
<input
|
||||
onKeyUp={[Function value]}
|
||||
placeholder="Find users"
|
||||
/>
|
||||
<div class="channeldetails__searchedusers">
|
||||
<a
|
||||
href="/some_path1"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
i am user1
|
||||
</a>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
onClick={[Function value]}
|
||||
data-content="user_id1"
|
||||
>
|
||||
Invite
|
||||
</button>
|
||||
</div>
|
||||
<div class="channeldetails__searchedusers">
|
||||
<a
|
||||
href="/some_path2"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
i am user2
|
||||
</a>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
onClick={[Function value]}
|
||||
data-content="user_id2"
|
||||
>
|
||||
Invite
|
||||
</button>
|
||||
</div>
|
||||
<div class="channeldetails__searchedusers">
|
||||
<a
|
||||
href="/some_path3"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
i am user3
|
||||
</a>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
onClick={[Function value]}
|
||||
data-content="user_id3"
|
||||
>
|
||||
Invite
|
||||
</button>
|
||||
</div>
|
||||
<h2>Pending Invites:</h2>
|
||||
<div class="channeldetails__pendingusers">
|
||||
<a
|
||||
href="/pendinguser1"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
data-content="users/pendingid1"
|
||||
>
|
||||
@pendinguser1 - pending user 1
|
||||
</a>
|
||||
</div>
|
||||
<div class="channeldetails__pendingusers">
|
||||
<a
|
||||
href="/pendinguser2"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
data-content="users/pendingid2"
|
||||
>
|
||||
@pendinguser2 - pending user 2
|
||||
</a>
|
||||
</div>
|
||||
<div style="margin-top: 10px;">
|
||||
All functionality is early beta. Contact us if you need help with anything.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
`;
|
||||
|
||||
exports[`<ChannelDetails /> as a user should leave channel and show appropriate message 1`] = `
|
||||
preact-render-spy (1 nodes)
|
||||
-------
|
||||
<div class="channeldetails">
|
||||
<h1 class="channeldetails__name">channel name</h1>
|
||||
<div
|
||||
class="channeldetails__description"
|
||||
style="margin-bottom: 20px;"
|
||||
>
|
||||
<em>something about this channel</em>
|
||||
</div>
|
||||
<div class="channeldetails__user">
|
||||
<a
|
||||
href="/channeluser1"
|
||||
style="padding: 3px 0px;"
|
||||
data-content="users/by_username?url=channeluser1"
|
||||
>
|
||||
channel user 1
|
||||
</a>
|
||||
</div>
|
||||
<div class="channeldetails__user">
|
||||
<a
|
||||
href="/channeluser2"
|
||||
style="padding: 3px 0px;"
|
||||
data-content="users/by_username?url=channeluser2"
|
||||
>
|
||||
channel user 2
|
||||
</a>
|
||||
</div>
|
||||
<div class="channeldetails__leftchannel">
|
||||
<h2>Danger Zone</h2>
|
||||
<h3>
|
||||
You have left this channel
|
||||
<span
|
||||
role="img"
|
||||
aria-label="emoji"
|
||||
>
|
||||
😢😢😢
|
||||
</span>
|
||||
</h3>
|
||||
<h4>It may not be immediately in the sidebar</h4>
|
||||
<p>
|
||||
Contact the admins at
|
||||
<a href="mailto:yo@dev.to">yo@dev.to</a>
|
||||
if this was a mistake
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
`;
|
||||
|
||||
exports[`<ChannelDetails /> as a user should render and test snapshot 1`] = `
|
||||
<div
|
||||
class="channeldetails"
|
||||
>
|
||||
<h1
|
||||
class="channeldetails__name"
|
||||
>
|
||||
channel name
|
||||
</h1>
|
||||
<div
|
||||
class="channeldetails__description"
|
||||
style={
|
||||
Object {
|
||||
"marginBottom": "20px",
|
||||
}
|
||||
}
|
||||
>
|
||||
<em>
|
||||
something about this channel
|
||||
</em>
|
||||
</div>
|
||||
<div
|
||||
class="channeldetails__user"
|
||||
>
|
||||
<a
|
||||
data-content="users/by_username?url=channeluser1"
|
||||
href="/channeluser1"
|
||||
style={
|
||||
Object {
|
||||
"color": undefined,
|
||||
"padding": "3px 0px",
|
||||
}
|
||||
}
|
||||
>
|
||||
channel user 1
|
||||
</a>
|
||||
</div>
|
||||
<div
|
||||
class="channeldetails__user"
|
||||
>
|
||||
<a
|
||||
data-content="users/by_username?url=channeluser2"
|
||||
href="/channeluser2"
|
||||
style={
|
||||
Object {
|
||||
"color": undefined,
|
||||
"padding": "3px 0px",
|
||||
}
|
||||
}
|
||||
>
|
||||
channel user 2
|
||||
</a>
|
||||
</div>
|
||||
<div
|
||||
class="channeldetails__leavechannel"
|
||||
>
|
||||
<h2>
|
||||
Danger Zone
|
||||
</h2>
|
||||
<button
|
||||
Click={[Function]}
|
||||
data-content="12345"
|
||||
type="button"
|
||||
>
|
||||
Leave Channel.
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
|
@ -0,0 +1,290 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`<Channels /> expanded with chat channels should render and test snapshot 1`] = `
|
||||
<div
|
||||
class="chatchannels"
|
||||
>
|
||||
<div
|
||||
class="chatchannels__channelslist"
|
||||
id="chatchannels__channelslist"
|
||||
>
|
||||
<button
|
||||
class="chatchanneltabbutton"
|
||||
data-channel-id={12345}
|
||||
data-channel-slug="0"
|
||||
onClick={[Function]}
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
class="chatchanneltab chatchanneltab--active chatchanneltab--new"
|
||||
data-channel-id={12345}
|
||||
data-channel-slug="0"
|
||||
style={
|
||||
Object {
|
||||
"border": "1px solid #4e57ef",
|
||||
"boxShadow": "3px 3px 0px #4e57ef",
|
||||
}
|
||||
}
|
||||
>
|
||||
<span>
|
||||
<span
|
||||
class="chatchanneltabindicator chatchanneltabindicator--new"
|
||||
data-channel-id={12345}
|
||||
data-channel-slug="0"
|
||||
>
|
||||
<img
|
||||
alt="channel name 1"
|
||||
src=""
|
||||
/>
|
||||
</span>
|
||||
channel name 1
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
class="chatchanneltabbutton"
|
||||
data-channel-id={12345}
|
||||
data-channel-slug="@1"
|
||||
onClick={[Function]}
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
class="chatchanneltab chatchanneltab--active chatchanneltab--new"
|
||||
data-channel-id={12345}
|
||||
data-channel-slug="@1"
|
||||
style={
|
||||
Object {
|
||||
"border": "1px solid #222222",
|
||||
"boxShadow": "3px 3px 0px #222222",
|
||||
}
|
||||
}
|
||||
>
|
||||
<span>
|
||||
<span
|
||||
class="chatchanneltabindicator chatchanneltabindicator--new"
|
||||
data-channel-id={12345}
|
||||
data-channel-slug="@1"
|
||||
>
|
||||
<img
|
||||
alt="group channel 2"
|
||||
class="chatchanneltabindicatordirectimage"
|
||||
src="fake_profile_pic"
|
||||
/>
|
||||
</span>
|
||||
@1
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
class="chatchanneltabbutton"
|
||||
data-channel-id={67890}
|
||||
data-channel-slug="2"
|
||||
onClick={[Function]}
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
class="chatchanneltab chatchanneltab--inactive chatchanneltab--old"
|
||||
data-channel-id={67890}
|
||||
data-channel-slug="2"
|
||||
style={
|
||||
Object {
|
||||
"border": "1px solid transparent",
|
||||
"boxShadow": "3px 3px 0px transparent",
|
||||
}
|
||||
}
|
||||
>
|
||||
<span>
|
||||
<span
|
||||
class="chatchanneltabindicator chatchanneltabindicator--old"
|
||||
data-channel-id={67890}
|
||||
data-channel-slug="2"
|
||||
>
|
||||
<img
|
||||
alt="group channel 3"
|
||||
src=""
|
||||
/>
|
||||
</span>
|
||||
group channel 3
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="chatchannels__config"
|
||||
>
|
||||
<img
|
||||
alt=""
|
||||
src=""
|
||||
style={
|
||||
Object {
|
||||
"height": "18px",
|
||||
}
|
||||
}
|
||||
/>
|
||||
<div
|
||||
class="chatchannels__configmenu"
|
||||
>
|
||||
<a
|
||||
href="/settings"
|
||||
>
|
||||
DEV Settings
|
||||
</a>
|
||||
<a
|
||||
href="/report-abuse"
|
||||
>
|
||||
Report Abuse
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`<Channels /> expanded without chat channels should render and test snapshot 1`] = `
|
||||
<div
|
||||
class="chatchannels"
|
||||
>
|
||||
<div
|
||||
class="chatchannels__channelslist"
|
||||
id="chatchannels__channelslist"
|
||||
>
|
||||
<div
|
||||
class="chatchannels__channelslistheader"
|
||||
>
|
||||
<span
|
||||
aria-label="emoji"
|
||||
role="img"
|
||||
>
|
||||
👋
|
||||
</span>
|
||||
Welcome to
|
||||
<b>
|
||||
DEV Connect
|
||||
</b>
|
||||
! You may message anyone you mutually follow.
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="chatchannels__config"
|
||||
>
|
||||
<img
|
||||
alt=""
|
||||
src=""
|
||||
style={
|
||||
Object {
|
||||
"height": "18px",
|
||||
}
|
||||
}
|
||||
/>
|
||||
<div
|
||||
class="chatchannels__configmenu"
|
||||
>
|
||||
<a
|
||||
href="/settings"
|
||||
>
|
||||
DEV Settings
|
||||
</a>
|
||||
<a
|
||||
href="/report-abuse"
|
||||
>
|
||||
Report Abuse
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`<Channels /> not expanded with chat channels should render and test snapshot 1`] = `
|
||||
<div
|
||||
class="chatchannels"
|
||||
>
|
||||
<div
|
||||
class="chatchannels__channelslist"
|
||||
id="chatchannels__channelslist"
|
||||
>
|
||||
<button
|
||||
class="chatchanneltabbutton"
|
||||
data-channel-id={12345}
|
||||
data-channel-slug="0"
|
||||
onClick={[Function]}
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
class="chatchanneltab chatchanneltab--active chatchanneltab--new"
|
||||
data-channel-id={12345}
|
||||
data-channel-slug="0"
|
||||
style={
|
||||
Object {
|
||||
"border": "1px solid #4e57ef",
|
||||
"boxShadow": "3px 3px 0px #4e57ef",
|
||||
}
|
||||
}
|
||||
>
|
||||
channel name 1
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
class="chatchanneltabbutton"
|
||||
data-channel-id={12345}
|
||||
data-channel-slug="@1"
|
||||
onClick={[Function]}
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
class="chatchanneltab chatchanneltab--active chatchanneltab--new"
|
||||
data-channel-id={12345}
|
||||
data-channel-slug="@1"
|
||||
style={
|
||||
Object {
|
||||
"border": "1px solid #222222",
|
||||
"boxShadow": "3px 3px 0px #222222",
|
||||
}
|
||||
}
|
||||
>
|
||||
<span
|
||||
class="chatchanneltabindicator chatchanneltabindicator--new"
|
||||
data-channel-id={12345}
|
||||
data-channel-slug="@1"
|
||||
>
|
||||
<img
|
||||
alt="group channel 2"
|
||||
class="chatchanneltabindicatordirectimage"
|
||||
src="fake_profile_pic"
|
||||
/>
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
class="chatchanneltabbutton"
|
||||
data-channel-id={67890}
|
||||
data-channel-slug="2"
|
||||
onClick={[Function]}
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
class="chatchanneltab chatchanneltab--inactive chatchanneltab--old"
|
||||
data-channel-id={67890}
|
||||
data-channel-slug="2"
|
||||
style={
|
||||
Object {
|
||||
"border": "1px solid transparent",
|
||||
"boxShadow": "3px 3px 0px transparent",
|
||||
}
|
||||
}
|
||||
>
|
||||
group channel 3
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`<Channels /> not expanded without chat channels should render and test snapshot 1`] = `
|
||||
<div
|
||||
class="chatchannels"
|
||||
>
|
||||
<div
|
||||
class="chatchannels__channelslist"
|
||||
id="chatchannels__channelslist"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
240
app/javascript/chat/__tests__/__snapshots__/chat.test.jsx.snap
Normal file
240
app/javascript/chat/__tests__/__snapshots__/chat.test.jsx.snap
Normal file
|
|
@ -0,0 +1,240 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`<Chat /> should load chat 1`] = `
|
||||
<div
|
||||
class="chat chat--expanded"
|
||||
data-no-instant={true}
|
||||
>
|
||||
<div
|
||||
class="chat__channels chat__channels--expanded"
|
||||
>
|
||||
<button
|
||||
class="chat__channelstogglebutt"
|
||||
onClick={[Function]}
|
||||
>
|
||||
<
|
||||
</button>
|
||||
<input
|
||||
onKeyUp={[Function]}
|
||||
placeholder="Filter"
|
||||
/>
|
||||
<div
|
||||
class="chat__channeltypefilter"
|
||||
>
|
||||
<button
|
||||
class="chat__channeltypefilterbutton chat__channeltypefilterbutton--active"
|
||||
data-channel-type="all"
|
||||
onClick={[Function]}
|
||||
>
|
||||
all
|
||||
</button>
|
||||
<button
|
||||
class="chat__channeltypefilterbutton chat__channeltypefilterbutton--inactive"
|
||||
data-channel-type="direct"
|
||||
onClick={[Function]}
|
||||
>
|
||||
direct
|
||||
</button>
|
||||
<button
|
||||
class="chat__channeltypefilterbutton chat__channeltypefilterbutton--inactive"
|
||||
data-channel-type="invite_only"
|
||||
onClick={[Function]}
|
||||
>
|
||||
group
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="chatchannels"
|
||||
>
|
||||
<div
|
||||
class="chatchannels__channelslist"
|
||||
id="chatchannels__channelslist"
|
||||
>
|
||||
<button
|
||||
class="chatchanneltabbutton"
|
||||
data-channel-id={12345}
|
||||
data-channel-slug="0"
|
||||
onClick={[Function]}
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
class="chatchanneltab chatchanneltab--inactive chatchanneltab--new"
|
||||
data-channel-id={12345}
|
||||
data-channel-slug="0"
|
||||
style={
|
||||
Object {
|
||||
"border": "1px solid transparent",
|
||||
"boxShadow": "3px 3px 0px transparent",
|
||||
}
|
||||
}
|
||||
>
|
||||
<span>
|
||||
<span
|
||||
class="chatchanneltabindicator chatchanneltabindicator--new"
|
||||
data-channel-id={12345}
|
||||
data-channel-slug="0"
|
||||
>
|
||||
<img
|
||||
alt="channel name 1"
|
||||
src=""
|
||||
/>
|
||||
</span>
|
||||
channel name 1
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
class="chatchanneltabbutton"
|
||||
data-channel-id={34561}
|
||||
data-channel-slug="@1"
|
||||
onClick={[Function]}
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
class="chatchanneltab chatchanneltab--active chatchanneltab--new"
|
||||
data-channel-id={34561}
|
||||
data-channel-slug="@1"
|
||||
style={
|
||||
Object {
|
||||
"border": "1px solid #222222",
|
||||
"boxShadow": "3px 3px 0px #222222",
|
||||
}
|
||||
}
|
||||
>
|
||||
<span>
|
||||
<span
|
||||
class="chatchanneltabindicator chatchanneltabindicator--new"
|
||||
data-channel-id={34561}
|
||||
data-channel-slug="@1"
|
||||
>
|
||||
<img
|
||||
alt="group channel 2"
|
||||
class="chatchanneltabindicatordirectimage"
|
||||
src="fake_profile_pic"
|
||||
/>
|
||||
</span>
|
||||
@1
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
class="chatchanneltabbutton"
|
||||
data-channel-id={67890}
|
||||
data-channel-slug="2"
|
||||
onClick={[Function]}
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
class="chatchanneltab chatchanneltab--inactive chatchanneltab--old"
|
||||
data-channel-id={67890}
|
||||
data-channel-slug="2"
|
||||
style={
|
||||
Object {
|
||||
"border": "1px solid transparent",
|
||||
"boxShadow": "3px 3px 0px transparent",
|
||||
}
|
||||
}
|
||||
>
|
||||
<span>
|
||||
<span
|
||||
class="chatchanneltabindicator chatchanneltabindicator--old"
|
||||
data-channel-id={67890}
|
||||
data-channel-slug="2"
|
||||
>
|
||||
<img
|
||||
alt="group channel 3"
|
||||
src=""
|
||||
/>
|
||||
</span>
|
||||
group channel 3
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="chatchannels__config"
|
||||
>
|
||||
<img
|
||||
alt=""
|
||||
src=""
|
||||
style={
|
||||
Object {
|
||||
"height": "18px",
|
||||
}
|
||||
}
|
||||
/>
|
||||
<div
|
||||
class="chatchannels__configmenu"
|
||||
>
|
||||
<a
|
||||
href="/settings"
|
||||
>
|
||||
DEV Settings
|
||||
</a>
|
||||
<a
|
||||
href="/report-abuse"
|
||||
>
|
||||
Report Abuse
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="chat__activechat"
|
||||
>
|
||||
<div
|
||||
class="activechatchannel"
|
||||
>
|
||||
<div
|
||||
class="activechatchannel__conversation"
|
||||
>
|
||||
<div
|
||||
class="activechatchannel__header"
|
||||
>
|
||||
|
||||
</div>
|
||||
<div
|
||||
class="activechatchannel__messages"
|
||||
id="messagelist"
|
||||
>
|
||||
<div
|
||||
class="messagelist__sentinel"
|
||||
id="messagelist__sentinel"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="activechatchannel__alerts"
|
||||
>
|
||||
<div
|
||||
class="chatalert__default chatalert__default--hidden"
|
||||
>
|
||||
More new messages below
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="activechatchannel__form"
|
||||
>
|
||||
<div
|
||||
class="messagecomposer"
|
||||
>
|
||||
<textarea
|
||||
class="messagecomposer__input"
|
||||
id="messageform"
|
||||
maxLength="1000"
|
||||
onKeyDown={[Function]}
|
||||
placeholder="Message goes here"
|
||||
/>
|
||||
<button
|
||||
class="messagecomposer__submit"
|
||||
onClick={[Function]}
|
||||
>
|
||||
SEND
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`<Content /> as loading-user should render and test snapshot 1`] = `
|
||||
<div
|
||||
class="activechatchannel__activecontent"
|
||||
id="chat_activecontent"
|
||||
onClick={false}
|
||||
>
|
||||
<button
|
||||
class="activechatchannel__activecontentexitbutton"
|
||||
data-content="exit"
|
||||
>
|
||||
×
|
||||
</button>
|
||||
<div
|
||||
style={
|
||||
Object {
|
||||
"backgroundColor": "#f5f6f7",
|
||||
"borderRadius": "500px",
|
||||
"display": "block",
|
||||
"height": "210px",
|
||||
"margin": " 15px auto",
|
||||
"width": "210px",
|
||||
}
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
|
@ -1,12 +1,12 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`<GithubRepo /> with fake token should have the proper elements, attributes and values with states set 1`] = `
|
||||
exports[`<GithubRepo /> with fake token should render and test snapshot 1`] = `
|
||||
preact-render-spy (1 nodes)
|
||||
-------
|
||||
<div class="activecontent__githubrepo">
|
||||
<div class="activecontent__githubrepoheader">
|
||||
<a href="/Users/benhalpern/dev/dev.to_core/app"></a>
|
||||
someargs
|
||||
invalid json response body at undefined reason: Unexpected end of JSON input
|
||||
</div>
|
||||
<div class="activecontent__githubrepofiles">
|
||||
<div class="activecontent__githubrepofilerow">
|
||||
|
|
@ -60,31 +60,10 @@ preact-render-spy (1 nodes)
|
|||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<p>SOMETHING READ ME BLAHHHH</p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
`;
|
||||
|
||||
exports[`<GithubRepo /> with fake token should render and test snapshot 1`] = `
|
||||
<div
|
||||
class="activecontent__githubrepo"
|
||||
>
|
||||
<div
|
||||
class="activecontent__githubrepoheader"
|
||||
>
|
||||
<a
|
||||
href="/Users/benhalpern/dev/dev.to_core/app"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="activecontent__githubrepofiles"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`<GithubRepo /> with no token should render and test snapshot 1`] = `
|
||||
<div
|
||||
class="activecontent__githubrepo"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,31 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`<Video /> should render properly and test snapshot 1`] = `
|
||||
<div
|
||||
class="chat__videocall"
|
||||
draggable="true"
|
||||
id="chat__videocall"
|
||||
onDrag={[Function]}
|
||||
style={
|
||||
Object {
|
||||
"left": "200px",
|
||||
"top": "200px",
|
||||
}
|
||||
}
|
||||
>
|
||||
<div
|
||||
class="chat__remotevideoscreen-0"
|
||||
id="videoremotescreen"
|
||||
/>
|
||||
<div
|
||||
class="chat__localvideoscren"
|
||||
id="videolocalscreen"
|
||||
/>
|
||||
<button
|
||||
class="chat__videocallexitbutton"
|
||||
onClick={[Function]}
|
||||
>
|
||||
×
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
|
|
@ -4,31 +4,39 @@ import { shallow } from 'preact-render-spy';
|
|||
import Alert from '../alert';
|
||||
|
||||
describe('<Alert />', () => {
|
||||
it('should render and test snapshot', () => {
|
||||
const tree = render(<Alert showAlert />);
|
||||
expect(tree).toMatchSnapshot();
|
||||
describe('without hidden class', () => {
|
||||
it('should render and test snapshot', () => {
|
||||
const tree = render(<Alert showAlert />);
|
||||
expect(tree).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should have proper elements, attributes and values', () => {
|
||||
const context = shallow(<Alert showAlert />);
|
||||
expect(context.find('.chatalert__default').exists()).toEqual(true);
|
||||
expect(context.find('.chatalert__default').text()).toEqual(
|
||||
'More new messages below',
|
||||
);
|
||||
expect(context.find('.chatalert__default--hidden').exists()).toEqual(
|
||||
false,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('should render and test snapshot with hidden class', () => {
|
||||
const tree = render(<Alert showAlert={false} />);
|
||||
expect(tree).toMatchSnapshot();
|
||||
});
|
||||
describe('with hidden class', () => {
|
||||
it('should render and test snapshot', () => {
|
||||
const tree = render(<Alert showAlert={false} />);
|
||||
expect(tree).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should have div without hidden class', () => {
|
||||
const context = shallow(<Alert showAlert />);
|
||||
expect(context.find('.chatalert__default').exists()).toEqual(true);
|
||||
expect(context.find('.chatalert__default').text()).toEqual(
|
||||
'More new messages below',
|
||||
);
|
||||
expect(context.find('.chatalert__default--hidden').exists()).toEqual(false);
|
||||
});
|
||||
|
||||
it('should have div with hidden class', () => {
|
||||
const context = shallow(<Alert showAlert={false} />);
|
||||
expect(context.find('.chatalert__default').exists()).toEqual(true);
|
||||
expect(context.find('.chatalert__default').text()).toEqual(
|
||||
'More new messages below',
|
||||
);
|
||||
expect(context.find('.chatalert__default--hidden').exists()).toEqual(true);
|
||||
it('should have proper elements, attributes and values', () => {
|
||||
const context = shallow(<Alert showAlert={false} />);
|
||||
expect(context.find('.chatalert__default').exists()).toEqual(true);
|
||||
expect(context.find('.chatalert__default').text()).toEqual(
|
||||
'More new messages below',
|
||||
);
|
||||
expect(context.find('.chatalert__default--hidden').exists()).toEqual(
|
||||
true,
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
125
app/javascript/chat/__tests__/article.test.jsx
Normal file
125
app/javascript/chat/__tests__/article.test.jsx
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
import { h } from 'preact';
|
||||
import render from 'preact-render-to-json';
|
||||
import { shallow } from 'preact-render-spy';
|
||||
import fetch from 'jest-fetch-mock';
|
||||
import Article from '../article';
|
||||
|
||||
global.fetch = fetch;
|
||||
|
||||
function flushPromises() {
|
||||
return new Promise(resolve => setImmediate(resolve));
|
||||
}
|
||||
|
||||
const sampleResponse = JSON.stringify({
|
||||
current_user: { id: 10000 },
|
||||
article_reaction_counts: [
|
||||
{ category: 'like', count: 150 },
|
||||
{ category: 'readinglist', count: 17 },
|
||||
{ category: 'unicorn', count: 48 },
|
||||
],
|
||||
reactions: [
|
||||
{
|
||||
id: 10000,
|
||||
user_id: 10000,
|
||||
reactable_id: 10000,
|
||||
reactable_type: 'Article',
|
||||
category: 'like',
|
||||
points: 1.0,
|
||||
created_at: '2018-10-30T20:34:01.503Z',
|
||||
updated_at: '2018-10-30T20:34:01.503Z',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const userArticle = {
|
||||
type_of: 'article',
|
||||
id: '42640',
|
||||
cover_image: 'princess_carolyn_is_perfect.png',
|
||||
path: '/princesscarolyn/your-approval-means-nothing-to-me-42640',
|
||||
title: 'Your Approval Means Nothing to Me',
|
||||
readable_publish_date: 'July 30, 2014',
|
||||
body_html:
|
||||
"That woman can knock a drink back like a Kennedy at a wake for another Kennedy, but I'll be damned if she doesn't get s*** done!",
|
||||
user: {
|
||||
id: '00001',
|
||||
username: 'princesscarolyn',
|
||||
name: 'Princess Carolyn',
|
||||
profile_image_90: '/princesscarolyn.png',
|
||||
},
|
||||
};
|
||||
|
||||
const getArticle = () => <Article resource={userArticle} />;
|
||||
|
||||
describe('<Article />', () => {
|
||||
it('should load article', async () => {
|
||||
const tree = render(getArticle());
|
||||
await flushPromises();
|
||||
expect(tree).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should have the proper elements, attributes and values', async () => {
|
||||
await fetch.mockResponseOnce(sampleResponse);
|
||||
const context = shallow(getArticle());
|
||||
await flushPromises();
|
||||
|
||||
// checks that article details are placed at their appropriate elements
|
||||
expect(context.find('.activechatchannel__activeArticle').exists()).toEqual(
|
||||
true,
|
||||
);
|
||||
expect(
|
||||
context.find('.activechatchannel__activeArticleDetails').exists(),
|
||||
).toEqual(true);
|
||||
expect(
|
||||
context
|
||||
.find('.activechatchannel__activeArticleDetails')
|
||||
.childAt(0)
|
||||
.attr('href'),
|
||||
).toEqual(userArticle.path);
|
||||
expect(
|
||||
context.find('.activechatchannel__activeArticleDetailsPath').text(),
|
||||
).toEqual(userArticle.path);
|
||||
expect(
|
||||
context
|
||||
.find('.title')
|
||||
.childAt(0)
|
||||
.text(),
|
||||
).toEqual(userArticle.title);
|
||||
expect(context.find('.author').attr('href')).toEqual(
|
||||
`/${userArticle.user.username}`,
|
||||
);
|
||||
expect(context.find('.profile-pic').attr('src')).toEqual(
|
||||
userArticle.user.profile_image_90,
|
||||
);
|
||||
expect(context.find('.author').text()).toEqual(
|
||||
`${userArticle.user.name} | ${userArticle.readable_publish_date}`,
|
||||
);
|
||||
expect(context.find('.published-at').text()).toEqual(
|
||||
` | ${userArticle.readable_publish_date}`,
|
||||
);
|
||||
expect(
|
||||
context
|
||||
.find('.body')
|
||||
.childAt(0)
|
||||
.attr('dangerouslySetInnerHTML'),
|
||||
).toEqual({ __html: userArticle.body_html });
|
||||
|
||||
// checks reaction
|
||||
expect(
|
||||
context.find('.activechatchannel__activeArticleActions').exists(),
|
||||
).toEqual(true);
|
||||
expect(context.find('.heart-reaction-button').exists()).toEqual(true);
|
||||
expect(context.find('.unicorn-reaction-button').exists()).toEqual(true);
|
||||
expect(context.find('.readinglist-reaction-button').exists()).toEqual(true);
|
||||
|
||||
// checks that only heart class has active
|
||||
expect(context.find('.heart-reaction-button').attr('className')).toEqual(
|
||||
'heart-reaction-button active',
|
||||
);
|
||||
expect(context.find('.unicorn-reaction-button').attr('className')).toEqual(
|
||||
'unicorn-reaction-button ',
|
||||
);
|
||||
expect(
|
||||
context.find('.readinglist-reaction-button').attr('className'),
|
||||
).toEqual('readinglist-reaction-button ');
|
||||
});
|
||||
});
|
||||
273
app/javascript/chat/__tests__/channelDetails.test.jsx
Normal file
273
app/javascript/chat/__tests__/channelDetails.test.jsx
Normal file
|
|
@ -0,0 +1,273 @@
|
|||
import { h } from 'preact';
|
||||
import render from 'preact-render-to-json';
|
||||
import { shallow } from 'preact-render-spy';
|
||||
import { JSDOM } from 'jsdom';
|
||||
import fetch from 'jest-fetch-mock';
|
||||
import ChannelDetails from '../channelDetails';
|
||||
import algoliasearch from '../__mocks__/algoliasearchUsers';
|
||||
|
||||
global.fetch = fetch;
|
||||
const doc = new JSDOM('<!doctype html><html><body></body></html>');
|
||||
global.document = doc;
|
||||
global.window = doc.defaultView;
|
||||
global.window.algoliasearch = algoliasearch;
|
||||
global.window.currentUser = { id: 'modID' };
|
||||
|
||||
const channelDetails = mod => {
|
||||
let id;
|
||||
if (mod) {
|
||||
id = 'modID';
|
||||
} else {
|
||||
id = 'userID';
|
||||
}
|
||||
return {
|
||||
channel_name: 'channel name',
|
||||
description: 'something about this channel',
|
||||
id: '12345',
|
||||
channel_users: [
|
||||
{
|
||||
name: 'channel user 1',
|
||||
username: 'channeluser1',
|
||||
},
|
||||
{
|
||||
name: 'channel user 2',
|
||||
username: 'channeluser2',
|
||||
},
|
||||
],
|
||||
type_of: 'channel-details',
|
||||
pending_users_select_fields: [
|
||||
{
|
||||
username: 'pendinguser1',
|
||||
id: 'pendingid1',
|
||||
name: 'pending user 1',
|
||||
},
|
||||
{
|
||||
username: 'pendinguser2',
|
||||
id: 'pendingid2',
|
||||
name: 'pending user 2',
|
||||
},
|
||||
],
|
||||
channel_mod_ids: id,
|
||||
};
|
||||
};
|
||||
|
||||
const getChannelDetails = details => (
|
||||
<ChannelDetails channel={details} activeChannelId={12345} />
|
||||
);
|
||||
|
||||
describe('<ChannelDetails />', () => {
|
||||
describe('as a moderator', () => {
|
||||
const moddetails = channelDetails(true);
|
||||
const context = shallow(getChannelDetails(moddetails));
|
||||
|
||||
it('should render and test snapshot', () => {
|
||||
const tree = render(getChannelDetails(moddetails));
|
||||
expect(tree).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should have the proper elements, attributes and content', () => {
|
||||
expect(context.find('.channeldetails').exists()).toEqual(true);
|
||||
expect(context.find('.channeldetails__name').text()).toEqual(
|
||||
moddetails.channel_name,
|
||||
);
|
||||
expect(context.find('.channeldetails__description').text()).toEqual(
|
||||
moddetails.description,
|
||||
);
|
||||
|
||||
// check user members
|
||||
const channelmembers = context.find('.channeldetails__user');
|
||||
expect(channelmembers.exists()).toEqual(true);
|
||||
for (let i = 0; i < channelmembers.length; i += 1) {
|
||||
expect(channelmembers.at(i).text()).toEqual(
|
||||
moddetails.channel_users[i].name,
|
||||
);
|
||||
expect(
|
||||
channelmembers
|
||||
.at(i)
|
||||
.childAt(0)
|
||||
.attr('href'),
|
||||
).toEqual(`/${moddetails.channel_users[i].username}`);
|
||||
expect(
|
||||
channelmembers
|
||||
.at(i)
|
||||
.childAt(0)
|
||||
.attr('data-content'),
|
||||
).toEqual(
|
||||
`users/by_username?url=${moddetails.channel_users[i].username}`,
|
||||
);
|
||||
}
|
||||
|
||||
// mod only divs
|
||||
expect(context.find('.channeldetails__searchedusers').exists()).toEqual(
|
||||
false,
|
||||
); // no searched users
|
||||
expect(context.find('.channeldetails__pendingusers').exists()).toEqual(
|
||||
true,
|
||||
);
|
||||
expect(context.find('.channeldetails__inviteusers').exists()).toEqual(
|
||||
true,
|
||||
);
|
||||
expect(context.find('.channeldetails__leftchannel').exists()).toEqual(
|
||||
false,
|
||||
);
|
||||
expect(context.find('.channeldetails__leavechannel').exists()).toEqual(
|
||||
false,
|
||||
);
|
||||
|
||||
// check pending members
|
||||
const pendingusers = context.find('.channeldetails__pendingusers');
|
||||
for (let i = 0; i < pendingusers.length; i += 1) {
|
||||
expect(pendingusers.at(i).text()).toEqual(
|
||||
`@${moddetails.pending_users_select_fields[i].username} - ${
|
||||
moddetails.pending_users_select_fields[i].name
|
||||
}`,
|
||||
);
|
||||
expect(
|
||||
pendingusers
|
||||
.at(i)
|
||||
.childAt(0)
|
||||
.attr('href'),
|
||||
).toEqual(`/${moddetails.pending_users_select_fields[i].username}`);
|
||||
expect(
|
||||
pendingusers
|
||||
.at(i)
|
||||
.childAt(0)
|
||||
.attr('data-content'),
|
||||
).toEqual(`users/${moddetails.pending_users_select_fields[i].id}`);
|
||||
}
|
||||
});
|
||||
|
||||
it('should search users and populate searched users div', async () => {
|
||||
// context.component().triggerUserSearch({ target: { value: 'ma', selectionStart: 2 } })
|
||||
const searchedusers = {
|
||||
searchedUsers: [
|
||||
{
|
||||
path: '/some_path1',
|
||||
title: 'i am user1',
|
||||
id: 'user_id1',
|
||||
},
|
||||
{
|
||||
path: '/some_path2',
|
||||
title: 'i am user2',
|
||||
id: 'user_id2',
|
||||
},
|
||||
{
|
||||
path: '/some_path3',
|
||||
title: 'i am user3',
|
||||
id: 'user_id3',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
context.setState(searchedusers);
|
||||
context.rerender();
|
||||
const searchedusersdivs = context.find('.channeldetails__searchedusers');
|
||||
expect(searchedusersdivs.exists()).toEqual(true);
|
||||
expect(searchedusersdivs.length).toEqual(3);
|
||||
|
||||
for (let i = 0; i < searchedusersdivs.length; i += 1) {
|
||||
expect(
|
||||
searchedusersdivs
|
||||
.at(i)
|
||||
.childAt(0)
|
||||
.attr('href'),
|
||||
).toEqual(searchedusers.searchedUsers[i].path);
|
||||
expect(
|
||||
searchedusersdivs
|
||||
.at(i)
|
||||
.childAt(0)
|
||||
.text(),
|
||||
).toEqual(searchedusers.searchedUsers[i].title);
|
||||
expect(
|
||||
searchedusersdivs
|
||||
.at(i)
|
||||
.childAt(2)
|
||||
.attr('data-content'),
|
||||
).toEqual(searchedusers.searchedUsers[i].id);
|
||||
expect(
|
||||
searchedusersdivs
|
||||
.at(i)
|
||||
.childAt(2)
|
||||
.text(),
|
||||
).toEqual('Invite');
|
||||
}
|
||||
|
||||
const tree = render(context);
|
||||
expect(tree).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
describe('as a user', () => {
|
||||
const userdetails = channelDetails(false);
|
||||
const context = shallow(getChannelDetails(userdetails));
|
||||
|
||||
it('should render and test snapshot', () => {
|
||||
const tree = render(getChannelDetails(userdetails));
|
||||
expect(tree).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should have the proper elements, attributes and content', () => {
|
||||
expect(context.find('.channeldetails').exists()).toEqual(true);
|
||||
expect(context.find('.channeldetails__name').text()).toEqual(
|
||||
userdetails.channel_name,
|
||||
);
|
||||
expect(context.find('.channeldetails__description').text()).toEqual(
|
||||
userdetails.description,
|
||||
);
|
||||
|
||||
const channelmembers = context.find('.channeldetails__user');
|
||||
expect(channelmembers.exists()).toEqual(true);
|
||||
for (let i = 0; i < channelmembers.length; i += 1) {
|
||||
expect(channelmembers.at(i).text()).toEqual(
|
||||
userdetails.channel_users[i].name,
|
||||
);
|
||||
expect(
|
||||
channelmembers
|
||||
.at(i)
|
||||
.childAt(0)
|
||||
.attr('href'),
|
||||
).toEqual(`/${userdetails.channel_users[i].username}`);
|
||||
expect(
|
||||
channelmembers
|
||||
.at(i)
|
||||
.childAt(0)
|
||||
.attr('data-content'),
|
||||
).toEqual(
|
||||
`users/by_username?url=${userdetails.channel_users[i].username}`,
|
||||
);
|
||||
}
|
||||
|
||||
// user only divs
|
||||
expect(context.find('.channeldetails__searchedusers').exists()).toEqual(
|
||||
false,
|
||||
);
|
||||
expect(context.find('.channeldetails__pendingusers').exists()).toEqual(
|
||||
false,
|
||||
);
|
||||
expect(context.find('.channeldetails__inviteusers').exists()).toEqual(
|
||||
false,
|
||||
);
|
||||
expect(context.find('.channeldetails__leftchannel').exists()).toEqual(
|
||||
false,
|
||||
);
|
||||
expect(context.find('.channeldetails__leavechannel').exists()).toEqual(
|
||||
true,
|
||||
);
|
||||
});
|
||||
|
||||
it('should leave channel and show appropriate message', () => {
|
||||
// leave channel
|
||||
context.component().handleLeaveChannelSuccess();
|
||||
context.rerender();
|
||||
expect(context.find('.channeldetails__leftchannel').exists()).toEqual(
|
||||
true,
|
||||
);
|
||||
expect(context.find('.channeldetails__leavechannel').exists()).toEqual(
|
||||
false,
|
||||
);
|
||||
|
||||
const tree = render(context);
|
||||
expect(tree).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
});
|
||||
248
app/javascript/chat/__tests__/channels.test.jsx
Normal file
248
app/javascript/chat/__tests__/channels.test.jsx
Normal file
|
|
@ -0,0 +1,248 @@
|
|||
import { h } from 'preact';
|
||||
import render from 'preact-render-to-json';
|
||||
import { shallow } from 'preact-render-spy';
|
||||
import { JSDOM } from 'jsdom';
|
||||
import Channels from '../channels';
|
||||
|
||||
const doc = new JSDOM('<!doctype html><html><body></body></html>');
|
||||
global.document = doc;
|
||||
global.window = doc.defaultView;
|
||||
global.window.currentUser = { id: 'fake_username' };
|
||||
|
||||
let channelSwitched = false;
|
||||
|
||||
const fakeSwitchChannel = () => {
|
||||
channelSwitched = !channelSwitched;
|
||||
};
|
||||
|
||||
const fakeChannels = [
|
||||
{
|
||||
channel_name: 'channel name 1',
|
||||
last_opened_at: 'September 2, 2018',
|
||||
channel_users: [],
|
||||
last_message_at: 'September 21, 2018',
|
||||
channel_type: 'group',
|
||||
slug: '0',
|
||||
id: 12345,
|
||||
messages_count: 124,
|
||||
},
|
||||
{
|
||||
channel_name: 'group channel 2',
|
||||
last_opened_at: 'September 12, 2018',
|
||||
channel_users: [
|
||||
{
|
||||
profile_image: 'fake_profile_image',
|
||||
darker_color: '#111111',
|
||||
last_opened_at: 'some last open date',
|
||||
},
|
||||
{
|
||||
profile_image: 'fake_profile_pic',
|
||||
darker_color: '#222222',
|
||||
last_opened_at: 'some other last open date',
|
||||
},
|
||||
],
|
||||
last_message_at: 'September 14, 2018',
|
||||
channel_type: 'direct',
|
||||
slug: '1',
|
||||
id: 12345,
|
||||
messages_count: 83,
|
||||
},
|
||||
{
|
||||
channel_name: 'group channel 3',
|
||||
last_opened_at: 'September 30, 2018',
|
||||
channel_users: [
|
||||
{
|
||||
profile_image: 'fake_profile_image',
|
||||
darker_color: '#111111',
|
||||
last_opened_at: 'some last open date',
|
||||
},
|
||||
{
|
||||
profile_image: 'fake_profile_pic',
|
||||
darker_color: '#222222',
|
||||
last_opened_at: 'some other last open date',
|
||||
},
|
||||
],
|
||||
last_message_at: 'September 29, 2018',
|
||||
channel_type: 'group',
|
||||
slug: '2',
|
||||
id: 67890,
|
||||
messages_count: 56,
|
||||
},
|
||||
];
|
||||
|
||||
const getChannels = (mod, chatChannels) => (
|
||||
<Channels
|
||||
incomingVideoCallChannelIds={[]} // no incoming calls
|
||||
activeChannelId={12345}
|
||||
chatChannels={chatChannels}
|
||||
handleSwitchChannel={fakeSwitchChannel}
|
||||
channelsLoaded
|
||||
filterQuery=""
|
||||
expanded={mod}
|
||||
/>
|
||||
);
|
||||
|
||||
describe('<Channels />', () => {
|
||||
describe('expanded', () => {
|
||||
describe('with chat channels', () => {
|
||||
it('should render and test snapshot', () => {
|
||||
const tree = render(getChannels(true, fakeChannels));
|
||||
expect(tree).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should have the proper elements, attributes, and content', () => {
|
||||
const context = shallow(getChannels(true, fakeChannels));
|
||||
|
||||
// configFooter should exist
|
||||
expect(context.find('.chatchannels__config').exists()).toEqual(true);
|
||||
expect(context.find('.chatchannels__configmenu').exists()).toEqual(
|
||||
true,
|
||||
);
|
||||
expect(
|
||||
context
|
||||
.find('.chatchannels__configmenu')
|
||||
.childAt(0)
|
||||
.text(),
|
||||
).toEqual('DEV Settings');
|
||||
expect(
|
||||
context
|
||||
.find('.chatchannels__configmenu')
|
||||
.childAt(0)
|
||||
.attr('href'),
|
||||
).toEqual('/settings');
|
||||
expect(
|
||||
context
|
||||
.find('.chatchannels__configmenu')
|
||||
.childAt(1)
|
||||
.text(),
|
||||
).toEqual('Report Abuse');
|
||||
expect(
|
||||
context
|
||||
.find('.chatchannels__configmenu')
|
||||
.childAt(1)
|
||||
.attr('href'),
|
||||
).toEqual('/report-abuse');
|
||||
|
||||
// welcome message should not exist because there are channels
|
||||
expect(
|
||||
context.find('.chatchannels__channelslistheader').exists(),
|
||||
).toEqual(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('without chat channels', () => {
|
||||
it('should render and test snapshot', () => {
|
||||
const tree = render(getChannels(true, []));
|
||||
expect(tree).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should have the proper elements, attributes, and content', () => {
|
||||
const context = shallow(getChannels(true, []));
|
||||
|
||||
// should show "Welcome to DEV Connect message....."
|
||||
expect(
|
||||
context.find('.chatchannels__channelslistheader').exists(),
|
||||
).toEqual(true);
|
||||
expect(
|
||||
context.find('.chatchannels__channelslistheader').text(),
|
||||
).toEqual(
|
||||
'👋 Welcome to DEV Connect! You may message anyone you mutually follow.',
|
||||
);
|
||||
|
||||
expect(context.find('.chatchannels__config').exists()).toEqual(true);
|
||||
expect(context.find('.chatchannels__configmenu').exists()).toEqual(
|
||||
true,
|
||||
);
|
||||
expect(
|
||||
context
|
||||
.find('.chatchannels__configmenu')
|
||||
.childAt(0)
|
||||
.text(),
|
||||
).toEqual('DEV Settings');
|
||||
expect(
|
||||
context
|
||||
.find('.chatchannels__configmenu')
|
||||
.childAt(0)
|
||||
.attr('href'),
|
||||
).toEqual('/settings');
|
||||
expect(
|
||||
context
|
||||
.find('.chatchannels__configmenu')
|
||||
.childAt(1)
|
||||
.text(),
|
||||
).toEqual('Report Abuse');
|
||||
expect(
|
||||
context
|
||||
.find('.chatchannels__configmenu')
|
||||
.childAt(1)
|
||||
.attr('href'),
|
||||
).toEqual('/report-abuse');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('not expanded', () => {
|
||||
describe('with chat channels', () => {
|
||||
it('should render and test snapshot', () => {
|
||||
const tree = render(getChannels(false, fakeChannels));
|
||||
expect(tree).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should have the proper elements, attributes, and content', () => {
|
||||
const context = shallow(getChannels(false, fakeChannels));
|
||||
|
||||
// should have group names but no user names
|
||||
expect(context.find('.chatchannels__channelslist').exists()).toEqual(
|
||||
true,
|
||||
);
|
||||
expect(
|
||||
context
|
||||
.find('.chatchannels__channelslist')
|
||||
.childAt(2)
|
||||
.attr('data-channel-slug'),
|
||||
).toEqual('@1'); // check user
|
||||
expect(
|
||||
context
|
||||
.find('.chatchannels__channelslist')
|
||||
.childAt(2)
|
||||
.text(),
|
||||
).toEqual(''); // ensure user has no text
|
||||
expect(
|
||||
context
|
||||
.find('.chatchannels__channelslist')
|
||||
.childAt(1)
|
||||
.text(),
|
||||
).toEqual(fakeChannels[0].channel_name);
|
||||
expect(
|
||||
context
|
||||
.find('.chatchannels__channelslist')
|
||||
.childAt(3)
|
||||
.text(),
|
||||
).toEqual(fakeChannels[2].channel_name);
|
||||
});
|
||||
});
|
||||
|
||||
describe('without chat channels', () => {
|
||||
it('should render and test snapshot', () => {
|
||||
const tree = render(getChannels(false, []));
|
||||
expect(tree).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should have the proper elements, attributes, and content', () => {
|
||||
const context = shallow(getChannels(false, []));
|
||||
|
||||
// should have nothing but empty str
|
||||
expect(context.find('.chatchannels__channelslist').exists()).toEqual(
|
||||
true,
|
||||
);
|
||||
expect(context.find('.chatchannels__channelslist').text()).toEqual('');
|
||||
expect(
|
||||
context.find('.chatchannels__channelslist').children().length,
|
||||
).toEqual(1);
|
||||
expect(
|
||||
context.find('.chatchannels__channelslist').children()[0],
|
||||
).toEqual(''); // empty child
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
142
app/javascript/chat/__tests__/chat.test.jsx
Normal file
142
app/javascript/chat/__tests__/chat.test.jsx
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
import { h } from 'preact';
|
||||
import render from 'preact-render-to-json';
|
||||
import { shallow } from 'preact-render-spy';
|
||||
import fetch from 'jest-fetch-mock';
|
||||
import { JSDOM } from 'jsdom';
|
||||
import Chat from '../chat';
|
||||
import algoliasearch from '../__mocks__/algoliasearchUsers';
|
||||
|
||||
global.fetch = fetch;
|
||||
|
||||
const doc = new JSDOM('<!doctype html><html><body></body></html>');
|
||||
global.document = doc;
|
||||
global.document.body.innerHTML =
|
||||
'<div class="chat chat--expanded" data-no-instant={true}><div class="chat__activechat"><div class="activechatchannel"><div class="activechatchannel__conversation"><div class="activechatchannel__header"></div><div class="activechatchannel__messages" id="messagelist"><div class="messagelist__sentinel" id="messagelist__sentinel"/></div><div class="activechatchannel__alerts"><div class="chatalert__default chatalert__default--hidden">More new messages below</div></div><div class="activechatchannel__form"><div class="messagecomposer"><textarea class="messagecomposer__input" id="messageform" maxLength="1000" onKeyDown={[Function]} placeholder="Message goes here" /><button class="messagecomposer__submit" onClick={[Function]}>SEND</button></div></div></div></div></div></div>';
|
||||
global.window = doc.defaultView;
|
||||
global.window.algoliasearch = algoliasearch;
|
||||
|
||||
// mock observer and user ID
|
||||
window.IntersectionObserver = jest.fn(function() {
|
||||
this.observe = jest.fn();
|
||||
});
|
||||
global.window.currentUser = { id: 'some_id' };
|
||||
|
||||
// fake props to pass to Chat
|
||||
const rootData = {
|
||||
algoliaId: 'somealgoliaid',
|
||||
algoliaIndex: 'somealgoliaindex',
|
||||
algoliaKey: 'somealgoliakey',
|
||||
chatChannels: JSON.stringify([
|
||||
{
|
||||
channel_name: 'channel name 1',
|
||||
last_opened_at: 'September 2, 2018',
|
||||
channel_users: [],
|
||||
last_message_at: 'September 21, 2018',
|
||||
channel_type: 'group',
|
||||
slug: '0',
|
||||
id: 12345,
|
||||
messages_count: 124,
|
||||
},
|
||||
{
|
||||
channel_name: 'group channel 2',
|
||||
last_opened_at: 'September 12, 2018',
|
||||
channel_users: [
|
||||
{
|
||||
profile_image: 'fake_profile_image',
|
||||
darker_color: '#111111',
|
||||
last_opened_at: 'some last open date',
|
||||
},
|
||||
{
|
||||
profile_image: 'fake_profile_pic',
|
||||
darker_color: '#222222',
|
||||
last_opened_at: 'some other last open date',
|
||||
},
|
||||
],
|
||||
last_message_at: 'September 14, 2018',
|
||||
channel_type: 'direct',
|
||||
slug: '1',
|
||||
id: 34561,
|
||||
messages_count: 83,
|
||||
},
|
||||
{
|
||||
channel_name: 'group channel 3',
|
||||
last_opened_at: 'September 30, 2018',
|
||||
channel_users: [
|
||||
{
|
||||
profile_image: 'fake_profile_image',
|
||||
darker_color: '#111111',
|
||||
last_opened_at: 'some last open date',
|
||||
},
|
||||
{
|
||||
profile_image: 'fake_profile_pic',
|
||||
darker_color: '#222222',
|
||||
last_opened_at: 'some other last open date',
|
||||
},
|
||||
],
|
||||
last_message_at: 'September 29, 2018',
|
||||
channel_type: 'group',
|
||||
slug: '2',
|
||||
id: 67890,
|
||||
messages_count: 56,
|
||||
},
|
||||
]),
|
||||
chatOptions: JSON.stringify({
|
||||
showChannelsList: true,
|
||||
showTimestamp: true,
|
||||
activeChannelId: 34561,
|
||||
}),
|
||||
githubToken: 'somegithubtoken',
|
||||
pusherKey: 'somepusherkey',
|
||||
};
|
||||
|
||||
const getChat = () => <Chat {...rootData} />;
|
||||
|
||||
describe('<Chat />', () => {
|
||||
it('should load chat', () => {
|
||||
const tree = render(getChat());
|
||||
expect(tree).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should have the proper elements, attributes and content', () => {
|
||||
const context = shallow(getChat());
|
||||
expect(context.exists()).toEqual(true);
|
||||
|
||||
expect(context.find('.chat').exists()).toEqual(true);
|
||||
expect(context.find('.chat--expanded').exists()).toEqual(true);
|
||||
expect(context.find('.chat__activechat').exists()).toEqual(true);
|
||||
|
||||
// renderChatChannels
|
||||
expect(context.find('.chat__channels').exists()).toEqual(true);
|
||||
expect(context.find('.chat__channelstogglebutt').exists()).toEqual(true);
|
||||
expect(context.find('.chat__channeltypefilter').exists()).toEqual(true);
|
||||
expect(context.find('.chat__channeltypefilter').text()).toEqual(
|
||||
'alldirectgroup',
|
||||
);
|
||||
|
||||
// renderActiveChatChannel
|
||||
expect(context.find('.activechatchannel').exists()).toEqual(true);
|
||||
expect(context.find('.activechatchannel__conversation').exists()).toEqual(
|
||||
true,
|
||||
);
|
||||
expect(context.find('.activechatchannel__header').exists()).toEqual(true);
|
||||
expect(context.find('.activechatchannel__messages').exists()).toEqual(true);
|
||||
expect(context.find('.activechatchannel__alerts').exists()).toEqual(true); // div that wraps Alert
|
||||
expect(context.find('.activechatchannel__form').exists()).toEqual(true); // div that wraps Compose
|
||||
});
|
||||
|
||||
it('should un-expand and expand chat channels properly', () => {
|
||||
const context = shallow(getChat());
|
||||
|
||||
// un-expand chat channels
|
||||
context.find('.chat__channelstogglebutt').simulate('click');
|
||||
expect(context.find('.chat__channeltypefilter').exists()).toEqual(false); // now hidden
|
||||
expect(context.find('.chat__channeltypefilter').text()).toEqual(''); // no text
|
||||
|
||||
// re-expand chat channel
|
||||
context.find('.chat__channelstogglebutt').simulate('click');
|
||||
expect(context.find('.chat__channeltypefilter').exists()).toEqual(true);
|
||||
expect(context.find('.chat__channeltypefilter').text()).toEqual(
|
||||
'alldirectgroup',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
@ -1,6 +1,5 @@
|
|||
import { h } from 'preact';
|
||||
import render from 'preact-render-to-json';
|
||||
// import { shallow } from 'preact-render-spy';
|
||||
import CodeEditor from '../codeEditor';
|
||||
|
||||
const getCodeEditor = () => (
|
||||
|
|
@ -12,11 +11,4 @@ describe('<CodeEditor />', () => {
|
|||
const tree = render(getCodeEditor());
|
||||
expect(tree).toMatchSnapshot();
|
||||
});
|
||||
|
||||
// it('should have the proper attributes and text values', () => {
|
||||
// const context = shallow(getCodeEditor());
|
||||
// expect(context.find('codeeditor').exists()).toEqual(true);
|
||||
// expect(context.find('.chatcodeeditor__header').exists()).toEqual(true);
|
||||
// expect(context.find('.chatcodeeditor__header').text()).toEqual('Experimental (WIP)');
|
||||
// });
|
||||
});
|
||||
|
|
|
|||
39
app/javascript/chat/__tests__/content.test.jsx
Normal file
39
app/javascript/chat/__tests__/content.test.jsx
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
import { h } from 'preact';
|
||||
import render from 'preact-render-to-json';
|
||||
import { shallow } from 'preact-render-spy';
|
||||
import Content from '../content';
|
||||
|
||||
const getContent = () => (
|
||||
<Content
|
||||
onTriggerContent={false}
|
||||
resource={{ type_of: 'loading-user' }}
|
||||
activeChannelId={12345}
|
||||
pusherKey="ASDFGHJKL"
|
||||
githubToken=""
|
||||
/>
|
||||
);
|
||||
|
||||
describe('<Content />', () => {
|
||||
describe('as loading-user', () => {
|
||||
it('should render and test snapshot', () => {
|
||||
const tree = render(getContent());
|
||||
expect(tree).toMatchSnapshot();
|
||||
});
|
||||
it('should have proper elements, attributes and content', () => {
|
||||
const context = shallow(getContent());
|
||||
expect(
|
||||
context.find('.activechatchannel__activecontent').exists(),
|
||||
).toEqual(true);
|
||||
const exitButton = context.find(
|
||||
'.activechatchannel__activecontentexitbutton',
|
||||
);
|
||||
expect(exitButton.exists()).toEqual(true);
|
||||
expect(exitButton.attr('data-content')).toEqual('exit');
|
||||
expect(exitButton.text()).toEqual('×');
|
||||
});
|
||||
});
|
||||
/*
|
||||
testing only as loading user since components that Content uses
|
||||
are independently tested
|
||||
*/
|
||||
});
|
||||
|
|
@ -2,11 +2,14 @@ import { h } from 'preact';
|
|||
import render from 'preact-render-to-json';
|
||||
import { shallow } from 'preact-render-spy';
|
||||
import fetch from 'jest-fetch-mock';
|
||||
import marked from 'marked';
|
||||
import GithubRepo from '../githubRepo';
|
||||
|
||||
global.fetch = fetch;
|
||||
|
||||
function flushPromises() {
|
||||
return new Promise(resolve => setImmediate(resolve));
|
||||
}
|
||||
|
||||
const getGithubRepo = token => (
|
||||
<GithubRepo
|
||||
activeChannelId={12345}
|
||||
|
|
@ -16,6 +19,117 @@ const getGithubRepo = token => (
|
|||
/>
|
||||
);
|
||||
|
||||
const contents = [
|
||||
{
|
||||
name: 'Camera',
|
||||
path: 'Camera',
|
||||
sha: 'hysst5jI2idHutihWo3JxYlTByoj0lkdXmkmuBEp',
|
||||
size: 0,
|
||||
url:
|
||||
'https://api.github.com/repos/username/repositoryname/contents/Camera?ref=master',
|
||||
html_url: 'https://github.com/username/repositoryname/tree/master/Camera',
|
||||
git_url:
|
||||
'https://api.github.com/repos/username/repositoryname/git/trees/hysst5jI2idHutihWo3JxYlTByoj0lkdXmkmuBEp',
|
||||
download_url: null,
|
||||
type: 'dir',
|
||||
_links: {
|
||||
self:
|
||||
'https://api.github.com/repos/username/repositoryname/contents/Camera?ref=master',
|
||||
git:
|
||||
'https://api.github.com/repos/username/repositoryname/git/trees/hysst5jI2idHutihWo3JxYlTByoj0lkdXmkmuBEp',
|
||||
html: 'https://github.com/username/repositoryname/tree/master/Camera',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Environment',
|
||||
path: 'Environment',
|
||||
sha: 'dwogYlYGQOXj1ru3L9HYfX7HdX3WNQPJgJVeStRs',
|
||||
size: 0,
|
||||
url:
|
||||
'https://api.github.com/repos/username/repositoryname/contents/Environment?ref=master',
|
||||
html_url:
|
||||
'https://github.com/username/repositoryname/tree/master/Environment',
|
||||
git_url:
|
||||
'https://api.github.com/repos/username/repositoryname/git/trees/dwogYlYGQOXj1ru3L9HYfX7HdX3WNQPJgJVeStRs',
|
||||
download_url: null,
|
||||
type: 'dir',
|
||||
_links: {
|
||||
self:
|
||||
'https://api.github.com/repos/username/repositoryname/contents/Environment?ref=master',
|
||||
git:
|
||||
'https://api.github.com/repos/username/repositoryname/git/trees/dwogYlYGQOXj1ru3L9HYfX7HdX3WNQPJgJVeStRs',
|
||||
html:
|
||||
'https://github.com/username/repositoryname/tree/master/Environment',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Interactables',
|
||||
path: 'Interactables',
|
||||
sha: '44OLxtYSQjr2DLVKPnwGTj6JuQpo7Te7pEIDULat',
|
||||
size: 0,
|
||||
url:
|
||||
'https://api.github.com/repos/username/repositoryname/contents/Interactables?ref=master',
|
||||
html_url:
|
||||
'https://github.com/username/repositoryname/tree/master/Interactables',
|
||||
git_url:
|
||||
'https://api.github.com/repos/username/repositoryname/git/trees/44OLxtYSQjr2DLVKPnwGTj6JuQpo7Te7pEIDULat',
|
||||
download_url: null,
|
||||
type: 'dir',
|
||||
_links: {
|
||||
self:
|
||||
'https://api.github.com/repos/username/repositoryname/contents/Interactables?ref=master',
|
||||
git:
|
||||
'https://api.github.com/repos/username/repositoryname/git/trees/44OLxtYSQjr2DLVKPnwGTj6JuQpo7Te7pEIDULat',
|
||||
html:
|
||||
'https://github.com/username/repositoryname/tree/master/Interactables',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Level Design',
|
||||
path: 'Level Design',
|
||||
sha: 'g178Oy2xV8gqFBhoaflJkSbHN01dxWEqjJTxw6Ax',
|
||||
size: 583,
|
||||
url:
|
||||
'https://api.github.com/repos/username/repositoryname/contents/Level%20Design?ref=master',
|
||||
html_url:
|
||||
'https://github.com/username/repositoryname/tree/master/Level%20Design',
|
||||
git_url:
|
||||
'https://api.github.com/repos/username/repositoryname/git/trees/g178Oy2xV8gqFBhoaflJkSbHN01dxWEqjJTxw6Ax',
|
||||
download_url:
|
||||
'https://raw.githubusercontent.com/username/repositoryname/master/Level%20Design',
|
||||
type: 'file',
|
||||
_links: {
|
||||
self:
|
||||
'https://api.github.com/repos/username/repositoryname/contents/Level%20Design?ref=master',
|
||||
git:
|
||||
'https://api.github.com/repos/username/repositoryname/git/trees/g178Oy2xV8gqFBhoaflJkSbHN01dxWEqjJTxw6Ax',
|
||||
html:
|
||||
'https://github.com/username/repositoryname/tree/master/Level%20Design',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Player',
|
||||
path: 'Player',
|
||||
sha: 'tia6ISq19krmOJzbtwpCTIuwRnvpSxZY2g1FMgOp',
|
||||
size: 1000,
|
||||
url:
|
||||
'https://api.github.com/repos/username/repositoryname/contents/Player?ref=master',
|
||||
html_url: 'https://github.com/username/repositoryname/tree/master/Player',
|
||||
git_url:
|
||||
'https://api.github.com/repos/username/repositoryname/git/trees/tia6ISq19krmOJzbtwpCTIuwRnvpSxZY2g1FMgOp',
|
||||
download_url:
|
||||
'https://raw.githubusercontent.com/username/repositoryname/master/Player',
|
||||
type: 'file',
|
||||
_links: {
|
||||
self:
|
||||
'https://api.github.com/repos/username/repositoryname/contents/Player?ref=master',
|
||||
git:
|
||||
'https://api.github.com/repos/username/repositoryname/git/trees/tia6ISq19krmOJzbtwpCTIuwRnvpSxZY2g1FMgOp',
|
||||
html: 'https://github.com/username/repositoryname/tree/master/Player',
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
describe('<GithubRepo />', () => {
|
||||
describe('with no token', () => {
|
||||
it('should render and test snapshot', () => {
|
||||
|
|
@ -31,161 +145,35 @@ describe('<GithubRepo />', () => {
|
|||
});
|
||||
|
||||
describe('with fake token', () => {
|
||||
it('should render and test snapshot', () => {
|
||||
const tree = render(getGithubRepo('some_token'));
|
||||
expect(tree).toMatchSnapshot();
|
||||
it('should render and test snapshot', async () => {
|
||||
await fetch.mockResponseOnce(JSON.stringify(contents));
|
||||
const context = shallow(getGithubRepo('some_token'));
|
||||
await flushPromises();
|
||||
expect(context).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should have the proper elements, attributes and values with states set', async () => {
|
||||
const context = await shallow(getGithubRepo('some_token'));
|
||||
const dirs = [
|
||||
{
|
||||
name: 'Camera',
|
||||
path: 'Camera',
|
||||
sha: 'hysst5jI2idHutihWo3JxYlTByoj0lkdXmkmuBEp',
|
||||
size: 0,
|
||||
url:
|
||||
'https://api.github.com/repos/username/repositoryname/contents/Camera?ref=master',
|
||||
html_url:
|
||||
'https://github.com/username/repositoryname/tree/master/Camera',
|
||||
git_url:
|
||||
'https://api.github.com/repos/username/repositoryname/git/trees/hysst5jI2idHutihWo3JxYlTByoj0lkdXmkmuBEp',
|
||||
download_url: null,
|
||||
type: 'dir',
|
||||
_links: {
|
||||
self:
|
||||
'https://api.github.com/repos/username/repositoryname/contents/Camera?ref=master',
|
||||
git:
|
||||
'https://api.github.com/repos/username/repositoryname/git/trees/hysst5jI2idHutihWo3JxYlTByoj0lkdXmkmuBEp',
|
||||
html:
|
||||
'https://github.com/username/repositoryname/tree/master/Camera',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Environment',
|
||||
path: 'Environment',
|
||||
sha: 'dwogYlYGQOXj1ru3L9HYfX7HdX3WNQPJgJVeStRs',
|
||||
size: 0,
|
||||
url:
|
||||
'https://api.github.com/repos/username/repositoryname/contents/Environment?ref=master',
|
||||
html_url:
|
||||
'https://github.com/username/repositoryname/tree/master/Environment',
|
||||
git_url:
|
||||
'https://api.github.com/repos/username/repositoryname/git/trees/dwogYlYGQOXj1ru3L9HYfX7HdX3WNQPJgJVeStRs',
|
||||
download_url: null,
|
||||
type: 'dir',
|
||||
_links: {
|
||||
self:
|
||||
'https://api.github.com/repos/username/repositoryname/contents/Environment?ref=master',
|
||||
git:
|
||||
'https://api.github.com/repos/username/repositoryname/git/trees/dwogYlYGQOXj1ru3L9HYfX7HdX3WNQPJgJVeStRs',
|
||||
html:
|
||||
'https://github.com/username/repositoryname/tree/master/Environment',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Interactables',
|
||||
path: 'Interactables',
|
||||
sha: '44OLxtYSQjr2DLVKPnwGTj6JuQpo7Te7pEIDULat',
|
||||
size: 0,
|
||||
url:
|
||||
'https://api.github.com/repos/username/repositoryname/contents/Interactables?ref=master',
|
||||
html_url:
|
||||
'https://github.com/username/repositoryname/tree/master/Interactables',
|
||||
git_url:
|
||||
'https://api.github.com/repos/username/repositoryname/git/trees/44OLxtYSQjr2DLVKPnwGTj6JuQpo7Te7pEIDULat',
|
||||
download_url: null,
|
||||
type: 'dir',
|
||||
_links: {
|
||||
self:
|
||||
'https://api.github.com/repos/username/repositoryname/contents/Interactables?ref=master',
|
||||
git:
|
||||
'https://api.github.com/repos/username/repositoryname/git/trees/44OLxtYSQjr2DLVKPnwGTj6JuQpo7Te7pEIDULat',
|
||||
html:
|
||||
'https://github.com/username/repositoryname/tree/master/Interactables',
|
||||
},
|
||||
},
|
||||
];
|
||||
context.setState({ directories: dirs });
|
||||
const fils = [
|
||||
{
|
||||
name: 'Level Design',
|
||||
path: 'Level Design',
|
||||
sha: 'g178Oy2xV8gqFBhoaflJkSbHN01dxWEqjJTxw6Ax',
|
||||
size: 583,
|
||||
url:
|
||||
'https://api.github.com/repos/username/repositoryname/contents/Level%20Design?ref=master',
|
||||
html_url:
|
||||
'https://github.com/username/repositoryname/tree/master/Level%20Design',
|
||||
git_url:
|
||||
'https://api.github.com/repos/username/repositoryname/git/trees/g178Oy2xV8gqFBhoaflJkSbHN01dxWEqjJTxw6Ax',
|
||||
download_url:
|
||||
'https://raw.githubusercontent.com/username/repositoryname/master/Level%20Design',
|
||||
type: 'file',
|
||||
_links: {
|
||||
self:
|
||||
'https://api.github.com/repos/username/repositoryname/contents/Level%20Design?ref=master',
|
||||
git:
|
||||
'https://api.github.com/repos/username/repositoryname/git/trees/g178Oy2xV8gqFBhoaflJkSbHN01dxWEqjJTxw6Ax',
|
||||
html:
|
||||
'https://github.com/username/repositoryname/tree/master/Level%20Design',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Player',
|
||||
path: 'Player',
|
||||
sha: 'tia6ISq19krmOJzbtwpCTIuwRnvpSxZY2g1FMgOp',
|
||||
size: 1000,
|
||||
url:
|
||||
'https://api.github.com/repos/username/repositoryname/contents/Player?ref=master',
|
||||
html_url:
|
||||
'https://github.com/username/repositoryname/tree/master/Player',
|
||||
git_url:
|
||||
'https://api.github.com/repos/username/repositoryname/git/trees/tia6ISq19krmOJzbtwpCTIuwRnvpSxZY2g1FMgOp',
|
||||
download_url:
|
||||
'https://raw.githubusercontent.com/username/repositoryname/master/Player',
|
||||
type: 'file',
|
||||
_links: {
|
||||
self:
|
||||
'https://api.github.com/repos/username/repositoryname/contents/Player?ref=master',
|
||||
git:
|
||||
'https://api.github.com/repos/username/repositoryname/git/trees/tia6ISq19krmOJzbtwpCTIuwRnvpSxZY2g1FMgOp',
|
||||
html:
|
||||
'https://github.com/username/repositoryname/tree/master/Player',
|
||||
},
|
||||
},
|
||||
];
|
||||
context.setState({ files: fils });
|
||||
const dirsfils = dirs.concat(fils);
|
||||
context.setState({ readme: 'SOMETHING READ ME BLAHHHH' });
|
||||
context.setState({ root: true });
|
||||
context.rerender();
|
||||
|
||||
const tree = render(context);
|
||||
expect(tree).toMatchSnapshot();
|
||||
await fetch.mockResponseOnce(JSON.stringify(contents));
|
||||
const context = shallow(getGithubRepo('some_token'));
|
||||
await flushPromises();
|
||||
|
||||
const len = context.find('.activecontent__githubrepofilerow').length;
|
||||
expect(len > 0).toEqual(true);
|
||||
for (let i = 0; i < len; i += 1) {
|
||||
const ghrow = context.find('.activecontent__githubrepofilerow').at(i);
|
||||
expect(ghrow.exists()).toEqual(true);
|
||||
if (dirsfils[i].type === 'dir') {
|
||||
expect(ghrow.text()).toEqual(`📁 ${dirsfils[i].name}`);
|
||||
if (contents[i].type === 'dir') {
|
||||
expect(ghrow.text()).toEqual(`📁 ${contents[i].name}`);
|
||||
} else {
|
||||
expect(ghrow.text()).toEqual(dirsfils[i].name);
|
||||
expect(ghrow.text()).toEqual(contents[i].name);
|
||||
}
|
||||
expect(ghrow.childAt(0).attr('href')).toEqual(dirsfils[i].html_url);
|
||||
expect(ghrow.childAt(0).attr('data-api-url')).toEqual(dirsfils[i].url);
|
||||
expect(ghrow.childAt(0).attr('data-path')).toEqual(dirsfils[i].path);
|
||||
expect(ghrow.childAt(0).attr('href')).toEqual(contents[i].html_url);
|
||||
expect(ghrow.childAt(0).attr('data-api-url')).toEqual(contents[i].url);
|
||||
expect(ghrow.childAt(0).attr('data-path')).toEqual(contents[i].path);
|
||||
}
|
||||
expect(context.find('.activecontent__githubrepoheader').text()).toEqual(
|
||||
context.state('path'),
|
||||
);
|
||||
expect(
|
||||
context
|
||||
.find('.activecontent__githubrepo')
|
||||
.childAt(2)
|
||||
.attr('dangerouslySetInnerHTML'),
|
||||
).toEqual({ __html: `${marked(context.state('readme'))}` });
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
48
app/javascript/chat/__tests__/video.test.jsx
Normal file
48
app/javascript/chat/__tests__/video.test.jsx
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
import { h } from 'preact';
|
||||
import render from 'preact-render-to-json';
|
||||
import { deep } from 'preact-render-spy';
|
||||
import fetch from 'jest-fetch-mock';
|
||||
import Video from '../video';
|
||||
|
||||
global.fetch = fetch;
|
||||
|
||||
let exited;
|
||||
exited = false;
|
||||
|
||||
const exitVideo = () => {
|
||||
exited = true;
|
||||
};
|
||||
|
||||
describe('<Video />', () => {
|
||||
it('should render properly and test snapshot', () => {
|
||||
const tree = render(<Video activeChannelId={12345} onExit={exitVideo} />);
|
||||
expect(tree).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should have the proper elements, classes and information', () => {
|
||||
const context = deep(<Video activeChannelId={12345} onExit={exitVideo} />);
|
||||
|
||||
// check elements
|
||||
expect(context.find('.chat__videocall').exists()).toEqual(true);
|
||||
expect(context.find('.chat__remotevideoscreen-0').exists()).toEqual(true);
|
||||
expect(context.find('.chat__localvideoscren').exists()).toEqual(true);
|
||||
const exitButton = context.find('.chat__videocallexitbutton');
|
||||
expect(exitButton.exists()).toEqual(true);
|
||||
expect(exitButton.text()).toEqual('×');
|
||||
|
||||
// test exit button behaves
|
||||
exitButton.simulate('click');
|
||||
expect(exited).toEqual(true);
|
||||
|
||||
// check initial state
|
||||
expect(context.state()).toEqual({
|
||||
leftPx: 200,
|
||||
topPx: 200,
|
||||
pageX: null,
|
||||
pageY: null,
|
||||
token: null,
|
||||
room: null,
|
||||
participants: [],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -1,21 +1,27 @@
|
|||
import { h, Component } from 'preact';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
const algoliaId = document.querySelector("meta[name='algolia-public-id']")
|
||||
.content;
|
||||
const algoliaKey = document.querySelector("meta[name='algolia-public-key']")
|
||||
.content;
|
||||
const env = document.querySelector("meta[name='environment']").content;
|
||||
const client = algoliasearch(algoliaId, algoliaKey);
|
||||
const index = client.initIndex(`searchables_${ env}`);
|
||||
class ChannelDetails extends Component {
|
||||
static propTypes = {
|
||||
channel: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
|
||||
};
|
||||
|
||||
export default class ChannelDetails extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
searchedUsers: [],
|
||||
invitations: [],
|
||||
// invitations: [],
|
||||
hasLeftChannel: false,
|
||||
};
|
||||
|
||||
const algoliaId = document.querySelector("meta[name='algolia-public-id']")
|
||||
.content;
|
||||
const algoliaKey = document.querySelector("meta[name='algolia-public-key']")
|
||||
.content;
|
||||
const env = document.querySelector("meta[name='environment']").content;
|
||||
const client = algoliasearch(algoliaId, algoliaKey); // eslint-disable-line no-undef
|
||||
this.index = client.initIndex(`searchables_${env}`);
|
||||
}
|
||||
|
||||
triggerUserSearch = e => {
|
||||
|
|
@ -28,7 +34,7 @@ export default class ChannelDetails extends Component {
|
|||
filters: 'class_name:User',
|
||||
};
|
||||
if (query.length > 0) {
|
||||
index.search(query, filters).then((content) => {
|
||||
this.index.search(query, filters).then(content => {
|
||||
component.setState({ searchedUsers: content.hits });
|
||||
});
|
||||
} else {
|
||||
|
|
@ -78,27 +84,27 @@ export default class ChannelDetails extends Component {
|
|||
.catch(null);
|
||||
};
|
||||
|
||||
handleLeaveChannelSuccess = response => {
|
||||
handleLeaveChannelSuccess = () => {
|
||||
this.setState({ hasLeftChannel: true });
|
||||
};
|
||||
|
||||
handleInvitationSuccess = response => {
|
||||
console.log(response);
|
||||
console.log(response); // eslint-disable-line no-console
|
||||
};
|
||||
|
||||
render() {
|
||||
const channel = this.props.channel;
|
||||
const channel = this.props.channel; // eslint-disable-line
|
||||
const users = Object.values(channel.channel_users).map(user => (
|
||||
<div>
|
||||
<div className="channeldetails__user">
|
||||
<a
|
||||
href={`/${ user.username}`}
|
||||
href={`/${user.username}`}
|
||||
style={{ color: user.darker_color, padding: '3px 0px' }}
|
||||
data-content={`users/by_username?url=${user.username}`}
|
||||
>
|
||||
{user.name}
|
||||
</a>
|
||||
</div>
|
||||
));
|
||||
));
|
||||
let subHeader = '';
|
||||
if (users.length === 80) {
|
||||
subHeader = <h3>Recently Active Members</h3>;
|
||||
|
|
@ -107,29 +113,41 @@ export default class ChannelDetails extends Component {
|
|||
let searchedUsers = [];
|
||||
let pendingInvites = [];
|
||||
if (channel.channel_mod_ids.includes(window.currentUser.id)) {
|
||||
// eslint-disable-next-line
|
||||
searchedUsers = this.state.searchedUsers.map(user => (
|
||||
<div>
|
||||
<a href={user.path} target="_blank">
|
||||
<div className="channeldetails__searchedusers">
|
||||
<a href={user.path} target="_blank" rel="noopener noreferrer">
|
||||
{user.title}
|
||||
</a>{' '}
|
||||
<button onClick={this.triggerInvite} data-content={user.id}>
|
||||
Invite
|
||||
</a>
|
||||
{' '}
|
||||
<button
|
||||
type="button"
|
||||
onClick={this.triggerInvite}
|
||||
data-content={user.id}
|
||||
>
|
||||
Invite
|
||||
</button>
|
||||
</div>
|
||||
));
|
||||
));
|
||||
pendingInvites = channel.pending_users_select_fields.map(user => (
|
||||
<div>
|
||||
<div className="channeldetails__pendingusers">
|
||||
<a
|
||||
href={`/${ user.username}`}
|
||||
href={`/${user.username}`}
|
||||
target="_blank"
|
||||
data-content={`users/${ user.id}`}
|
||||
rel="noopener noreferrer"
|
||||
data-content={`users/${user.id}`}
|
||||
>
|
||||
@{user.username} - {user.name}
|
||||
@
|
||||
{user.username}
|
||||
{' '}
|
||||
-
|
||||
{' '}
|
||||
{user.name}
|
||||
</a>
|
||||
</div>
|
||||
));
|
||||
));
|
||||
modSection = (
|
||||
<div>
|
||||
<div className="channeldetails__inviteusers">
|
||||
<h2>Invite Members</h2>
|
||||
<input onKeyUp={this.triggerUserSearch} placeholder="Find users" />
|
||||
{searchedUsers}
|
||||
|
|
@ -140,37 +158,51 @@ export default class ChannelDetails extends Component {
|
|||
anything.
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
); // eslint-disable-next-line
|
||||
} else if (this.state.hasLeftChannel) {
|
||||
modSection = (
|
||||
<div>
|
||||
<h2>Danger Zone</h2>
|
||||
<h3>You have left this channel 😢😢😢</h3>
|
||||
<h4>It may not be immediately in the sidebar</h4>
|
||||
<p>
|
||||
Contact the admins at <a href="mailto:yo@dev.to">yo@dev.to</a> if
|
||||
this was a mistake
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
modSection = (
|
||||
<div>
|
||||
<h2>Danger Zone</h2>
|
||||
<button
|
||||
onClick={this.triggerLeaveChannel}
|
||||
data-content={channel.id}
|
||||
>
|
||||
Leave Channel.
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
modSection = (
|
||||
<div className="channeldetails__leftchannel">
|
||||
<h2>Danger Zone</h2>
|
||||
<h3>
|
||||
You have left this channel
|
||||
{' '}
|
||||
<span role="img" aria-label="emoji">
|
||||
😢😢😢
|
||||
</span>
|
||||
</h3>
|
||||
<h4>It may not be immediately in the sidebar</h4>
|
||||
<p>
|
||||
Contact the admins at
|
||||
{' '}
|
||||
<a href="mailto:yo@dev.to">yo@dev.to</a>
|
||||
{' '}
|
||||
if
|
||||
this was a mistake
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
modSection = (
|
||||
<div className="channeldetails__leavechannel">
|
||||
<h2>Danger Zone</h2>
|
||||
<button
|
||||
type="button"
|
||||
Click={this.triggerLeaveChannel}
|
||||
data-content={channel.id}
|
||||
>
|
||||
Leave Channel.
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
<h1>{channel.channel_name}</h1>
|
||||
<div className="channeldetails">
|
||||
<h1 className="channeldetails__name">{channel.channel_name}</h1>
|
||||
{subHeader}
|
||||
<div style={{ marginBottom: '20px' }}>
|
||||
<div
|
||||
className="channeldetails__description"
|
||||
style={{ marginBottom: '20px' }}
|
||||
>
|
||||
<em>{channel.description || ''}</em>
|
||||
</div>
|
||||
{users}
|
||||
|
|
@ -179,3 +211,5 @@ export default class ChannelDetails extends Component {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default ChannelDetails;
|
||||
|
|
|
|||
|
|
@ -3,84 +3,116 @@ import PropTypes from 'prop-types';
|
|||
import ConfigImage from 'images/three-dots.svg';
|
||||
import GroupImage from 'images/organization.svg';
|
||||
|
||||
const Channels = ({ activeChannelId,
|
||||
chatChannels,
|
||||
handleSwitchChannel,
|
||||
expanded,
|
||||
filterQuery,
|
||||
channelsLoaded,
|
||||
incomingVideoCallChannelIds }) => {
|
||||
const channels = chatChannels.map((channel, index) => {
|
||||
if (!channel) { return}
|
||||
const isActive = parseInt(activeChannelId, 10) === channel.id
|
||||
let lastOpened = channel.last_opened_at
|
||||
const Channels = ({
|
||||
activeChannelId,
|
||||
chatChannels,
|
||||
handleSwitchChannel,
|
||||
expanded,
|
||||
filterQuery,
|
||||
channelsLoaded,
|
||||
incomingVideoCallChannelIds,
|
||||
}) => {
|
||||
const channels = chatChannels.map(channel => {
|
||||
if (!channel) {
|
||||
return;
|
||||
}
|
||||
const isActive = parseInt(activeChannelId, 10) === channel.id;
|
||||
let lastOpened = channel.last_opened_at;
|
||||
if (!lastOpened) {
|
||||
if (channel.channel_users[window.currentUser.username]) {
|
||||
lastOpened = channel.channel_users[window.currentUser.username].last_opened_at
|
||||
lastOpened =
|
||||
channel.channel_users[window.currentUser.username].last_opened_at;
|
||||
} else {
|
||||
lastOpened = new Date();
|
||||
}
|
||||
}
|
||||
const isUnopened = (new Date(channel.last_message_at) > new Date(lastOpened)) && channel.messages_count > 0;
|
||||
|
||||
const otherClassname =
|
||||
isActive
|
||||
? 'chatchanneltab--active'
|
||||
: 'chatchanneltab--inactive';
|
||||
const name = channel.channel_type === "direct" ? '@'+channel.slug.replace(`${window.currentUser.username}/`, '').replace(`/${window.currentUser.username}`, '') : channel.channel_name
|
||||
const newMessagesIndicatorClass = isUnopened ? "new" : "old"
|
||||
const modififedSlug = channel.channel_type === "direct" ? name : channel.slug;
|
||||
const indicatorPic = channel.channel_type === "direct" ? <img src = {channel.channel_users[name.replace('@','')].profile_image} className='chatchanneltabindicatordirectimage' /> : <img src={GroupImage} />
|
||||
let channelColor = 'transparent'
|
||||
if (channel.channel_type === "direct" && isActive) {
|
||||
channelColor = channel.channel_users[name.replace('@','')].darker_color;
|
||||
} else if ( isActive ) {
|
||||
channelColor = '#4e57ef'
|
||||
const isUnopened =
|
||||
new Date(channel.last_message_at) > new Date(lastOpened) &&
|
||||
channel.messages_count > 0;
|
||||
|
||||
const otherClassname = isActive
|
||||
? 'chatchanneltab--active'
|
||||
: 'chatchanneltab--inactive';
|
||||
const name =
|
||||
channel.channel_type === 'direct'
|
||||
? `@${channel.slug
|
||||
.replace(`${window.currentUser.username}/`, '')
|
||||
.replace(`/${window.currentUser.username}`, '')}`
|
||||
: channel.channel_name;
|
||||
const newMessagesIndicatorClass = isUnopened ? 'new' : 'old';
|
||||
const modififedSlug =
|
||||
channel.channel_type === 'direct' ? name : channel.slug;
|
||||
const indicatorPic =
|
||||
channel.channel_type === 'direct' ? (
|
||||
<img
|
||||
alt={channel.channel_name}
|
||||
src={channel.channel_users[name.replace('@', '')].profile_image}
|
||||
className="chatchanneltabindicatordirectimage"
|
||||
/>
|
||||
) : (
|
||||
<img alt={channel.channel_name} src={GroupImage} />
|
||||
);
|
||||
let channelColor = 'transparent';
|
||||
if (channel.channel_type === 'direct' && isActive) {
|
||||
channelColor = channel.channel_users[name.replace('@', '')].darker_color;
|
||||
} else if (isActive) {
|
||||
channelColor = '#4e57ef';
|
||||
}
|
||||
|
||||
let content = ''
|
||||
|
||||
let content = '';
|
||||
const contentInner = (
|
||||
<span
|
||||
data-channel-slug={modififedSlug}
|
||||
className={`chatchanneltabindicator chatchanneltabindicator--${newMessagesIndicatorClass}`}
|
||||
data-channel-id={channel.id}
|
||||
>
|
||||
{indicatorPic}
|
||||
</span>
|
||||
);
|
||||
if (expanded) {
|
||||
content = <span>
|
||||
<span
|
||||
data-channel-slug={modififedSlug}
|
||||
className={"chatchanneltabindicator chatchanneltabindicator--" + newMessagesIndicatorClass}
|
||||
data-channel-id={channel.id}
|
||||
data-channel-slug={modififedSlug}>
|
||||
{indicatorPic}
|
||||
</span>
|
||||
{name}
|
||||
</span>
|
||||
content = (
|
||||
<span>
|
||||
{contentInner}
|
||||
{name}
|
||||
</span>
|
||||
);
|
||||
} else if (channel.channel_type === 'direct') {
|
||||
content = contentInner;
|
||||
} else {
|
||||
if (channel.channel_type === "direct") {
|
||||
|
||||
content = <span
|
||||
data-channel-slug={modififedSlug}
|
||||
className={"chatchanneltabindicator chatchanneltabindicator--" + newMessagesIndicatorClass}
|
||||
data-channel-id={channel.id}
|
||||
data-channel-slug={modififedSlug}>
|
||||
{indicatorPic}
|
||||
</span>
|
||||
} else {
|
||||
content = name
|
||||
}
|
||||
content = name;
|
||||
}
|
||||
let callIndicator = ''
|
||||
if (incomingVideoCallChannelIds && incomingVideoCallChannelIds.includes(channel.id)) {
|
||||
callIndicator = <span className='chatchanneltabindicator chatchanneltabindicator--phone'>📞</span>
|
||||
let callIndicator = '';
|
||||
if (
|
||||
incomingVideoCallChannelIds &&
|
||||
incomingVideoCallChannelIds.includes(channel.id)
|
||||
) {
|
||||
callIndicator = (
|
||||
<span
|
||||
role="img"
|
||||
aria-label="emoji"
|
||||
className="chatchanneltabindicator chatchanneltabindicator--phone"
|
||||
>
|
||||
📞
|
||||
</span>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
key={channel.id}
|
||||
className='chatchanneltabbutton'
|
||||
className="chatchanneltabbutton"
|
||||
onClick={handleSwitchChannel}
|
||||
data-channel-id={channel.id}
|
||||
data-channel-slug={modififedSlug}
|
||||
>
|
||||
<span className={`chatchanneltab ${otherClassname} chatchanneltab--${newMessagesIndicatorClass}`}
|
||||
<span
|
||||
className={`chatchanneltab ${otherClassname} chatchanneltab--${newMessagesIndicatorClass}`}
|
||||
data-channel-id={channel.id}
|
||||
data-channel-slug={modififedSlug}
|
||||
style={{border:`1px solid ${channelColor}`, boxShadow: `3px 3px 0px ${channelColor}`}}
|
||||
style={{
|
||||
border: `1px solid ${channelColor}`,
|
||||
boxShadow: `3px 3px 0px ${channelColor}`,
|
||||
}}
|
||||
>
|
||||
{callIndicator}
|
||||
{content}
|
||||
|
|
@ -88,32 +120,49 @@ const Channels = ({ activeChannelId,
|
|||
</button>
|
||||
);
|
||||
});
|
||||
let channelsListFooter = ""
|
||||
let channelsListFooter = '';
|
||||
if (channels.length === 30) {
|
||||
channelsListFooter = <div className="chatchannels__channelslistfooter">...</div>
|
||||
channelsListFooter = (
|
||||
<div className="chatchannels__channelslistfooter">...</div>
|
||||
);
|
||||
}
|
||||
let topNotice = ''
|
||||
if (expanded &&
|
||||
let topNotice = '';
|
||||
if (
|
||||
expanded &&
|
||||
filterQuery.length === 0 &&
|
||||
channelsLoaded &&
|
||||
(channels.length === 0 || channels[0].messages_count === 0) ) {
|
||||
topNotice = <div className="chatchannels__channelslistheader">
|
||||
👋 Welcome to <b>DEV Connect</b>! You may message anyone you mutually follow.
|
||||
(channels.length === 0 || channels[0].messages_count === 0)
|
||||
) {
|
||||
topNotice = (
|
||||
<div className="chatchannels__channelslistheader">
|
||||
<span role="img" aria-label="emoji">
|
||||
👋
|
||||
</span>
|
||||
{' '}
|
||||
Welcome to
|
||||
<b> DEV Connect</b>
|
||||
! You may message anyone you mutually follow.
|
||||
</div>
|
||||
);
|
||||
}
|
||||
let configFooter = ''
|
||||
let configFooter = '';
|
||||
if (expanded) {
|
||||
configFooter = <div className="chatchannels__config">
|
||||
<img src={ConfigImage} style={{height: "18px"}}/>
|
||||
configFooter = (
|
||||
<div className="chatchannels__config">
|
||||
<img alt="" src={ConfigImage} style={{ height: '18px' }} />
|
||||
<div className="chatchannels__configmenu">
|
||||
<a href="/settings">DEV Settings</a>
|
||||
<a href="/report-abuse">Report Abuse</a>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<div className="chatchannels">
|
||||
<div className="chatchannels__channelslist" id="chatchannels__channelslist">
|
||||
<div
|
||||
className="chatchannels__channelslist"
|
||||
id="chatchannels__channelslist"
|
||||
>
|
||||
{topNotice}
|
||||
{channels}
|
||||
{channelsListFooter}
|
||||
|
|
@ -128,6 +177,9 @@ Channels.propTypes = {
|
|||
chatChannels: PropTypes.array.isRequired,
|
||||
handleSwitchChannel: PropTypes.func.isRequired,
|
||||
expanded: PropTypes.bool.isRequired,
|
||||
filterQuery: PropTypes.string.isRequired,
|
||||
channelsLoaded: PropTypes.bool.isRequired,
|
||||
incomingVideoCallChannelIds: PropTypes.array.isRequired,
|
||||
};
|
||||
|
||||
export default Channels;
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ module.exports = {
|
|||
'!**/__stories__/**',
|
||||
],
|
||||
moduleNameMapper: {
|
||||
'\\.(svg)$': '<rootDir>/empty-module.js',
|
||||
'\\.(svg|png)$': '<rootDir>/empty-module.js',
|
||||
},
|
||||
snapshotSerializers: ['preact-render-spy/snapshot'],
|
||||
};
|
||||
|
|
|
|||
|
|
@ -68,6 +68,7 @@
|
|||
"faker": "^4.1.0",
|
||||
"husky": "^1.1.4",
|
||||
"jest": "^23.5.0",
|
||||
"jsdom": "^13.0.0",
|
||||
"jest-fetch-mock": "^1.7.4",
|
||||
"lint-staged": "^8.0.5",
|
||||
"preact-render-spy": "^1.3.0",
|
||||
|
|
|
|||
118
yarn.lock
118
yarn.lock
|
|
@ -583,6 +583,14 @@ acorn-globals@^4.1.0:
|
|||
dependencies:
|
||||
acorn "^5.0.0"
|
||||
|
||||
acorn-globals@^4.3.0:
|
||||
version "4.3.0"
|
||||
resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-4.3.0.tgz#e3b6f8da3c1552a95ae627571f7dd6923bb54103"
|
||||
integrity sha512-hMtHj3s5RnuhvHPowpBYvJVj3rAar82JiDQHvGs1zO0l10ocX/xEdBShNHTJaboucJUsScghp74pH3s7EnHHQw==
|
||||
dependencies:
|
||||
acorn "^6.0.1"
|
||||
acorn-walk "^6.0.1"
|
||||
|
||||
acorn-jsx@^4.1.1:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-4.1.1.tgz#e8e41e48ea2fe0c896740610ab6a4ffd8add225e"
|
||||
|
|
@ -590,6 +598,11 @@ acorn-jsx@^4.1.1:
|
|||
dependencies:
|
||||
acorn "^5.0.3"
|
||||
|
||||
acorn-walk@^6.0.1:
|
||||
version "6.1.0"
|
||||
resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-6.1.0.tgz#c957f4a1460da46af4a0388ce28b4c99355b0cbc"
|
||||
integrity sha512-ugTb7Lq7u4GfWSqqpwE0bGyoBZNMTok/zDBXxfEG0QM50jNlGhIWjRC1pPN7bvV1anhF+bs+/gNcRw+o55Evbg==
|
||||
|
||||
acorn@^4.0.3:
|
||||
version "4.0.13"
|
||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.13.tgz#105495ae5361d697bd195c825192e1ad7f253787"
|
||||
|
|
@ -600,6 +613,11 @@ acorn@^5.0.0, acorn@^5.0.3, acorn@^5.5.3, acorn@^5.6.0:
|
|||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.3.tgz#67aa231bf8812974b85235a96771eb6bd07ea279"
|
||||
integrity sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==
|
||||
|
||||
acorn@^6.0.1, acorn@^6.0.2:
|
||||
version "6.0.4"
|
||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.0.4.tgz#77377e7353b72ec5104550aa2d2097a2fd40b754"
|
||||
integrity sha512-VY4i5EKSKkofY2I+6QLTbTTN/UvEQPCo6eiwzzSaSWfpaDhOmStMCMod6wmuPciNq+XS0faCglFu2lHZpdHUtg==
|
||||
|
||||
address@1.0.3, address@^1.0.1:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/address/-/address-1.0.3.tgz#b5f50631f8d6cec8bd20c963963afb55e06cbce9"
|
||||
|
|
@ -3162,12 +3180,12 @@ csso@~2.3.1:
|
|||
clap "^1.0.9"
|
||||
source-map "^0.5.3"
|
||||
|
||||
cssom@0.3.x, "cssom@>= 0.3.2 < 0.4.0":
|
||||
cssom@0.3.x, "cssom@>= 0.3.2 < 0.4.0", cssom@^0.3.4:
|
||||
version "0.3.4"
|
||||
resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.4.tgz#8cd52e8a3acfd68d3aed38ee0a640177d2f9d797"
|
||||
integrity sha512-+7prCSORpXNeR4/fUP3rL+TzqtiFfhMvTd7uEqMdgPvLPt4+uzFUeufx5RHjGTACCargg/DiEt/moMQmvnfkog==
|
||||
|
||||
cssstyle@^1.0.0:
|
||||
cssstyle@^1.0.0, cssstyle@^1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-1.1.1.tgz#18b038a9c44d65f7a8e428a653b9f6fe42faf5fb"
|
||||
integrity sha512-364AI1l/M5TYcFH83JnOH/pSqgaNnKmYgKrm0didZMGKWjQB60dymwWy1rKUgL3J1ffdq9xVi2yGLHdSjjSNog==
|
||||
|
|
@ -3224,6 +3242,15 @@ data-urls@^1.0.0:
|
|||
whatwg-mimetype "^2.1.0"
|
||||
whatwg-url "^7.0.0"
|
||||
|
||||
data-urls@^1.0.1:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-1.1.0.tgz#15ee0582baa5e22bb59c77140da8f9c76963bbfe"
|
||||
integrity sha512-YTWYI9se1P55u58gL5GkQHW4P6VJBJ5iBT+B5a7i2Tjadhv52paJG0qHX4A0OR6/t52odI64KP2YvFpkDOi3eQ==
|
||||
dependencies:
|
||||
abab "^2.0.0"
|
||||
whatwg-mimetype "^2.2.0"
|
||||
whatwg-url "^7.0.0"
|
||||
|
||||
date-fns@^1.27.2:
|
||||
version "1.29.0"
|
||||
resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-1.29.0.tgz#12e609cdcb935127311d04d33334e2960a2a54e6"
|
||||
|
|
@ -3767,7 +3794,7 @@ escape-string-regexp@1.0.5, escape-string-regexp@^1.0.2, escape-string-regexp@^1
|
|||
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
|
||||
integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
|
||||
|
||||
escodegen@^1.9.1:
|
||||
escodegen@^1.11.0, escodegen@^1.9.1:
|
||||
version "1.11.0"
|
||||
resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.11.0.tgz#b27a9389481d5bfd5bec76f7bb1eb3f8f4556589"
|
||||
integrity sha512-IeMV45ReixHS53K/OmfKAIztN/igDHzTJUhZM3k1jMhIZWjk45SMwAtBsEXiJp3vSPmTcu6CXn7mDvFHRN66fw==
|
||||
|
|
@ -5189,7 +5216,7 @@ iconv-lite@0.4.23:
|
|||
dependencies:
|
||||
safer-buffer ">= 2.1.2 < 3"
|
||||
|
||||
iconv-lite@^0.4.17, iconv-lite@^0.4.24, iconv-lite@^0.4.4, iconv-lite@~0.4.13:
|
||||
iconv-lite@0.4.24, iconv-lite@^0.4.17, iconv-lite@^0.4.24, iconv-lite@^0.4.4, iconv-lite@~0.4.13:
|
||||
version "0.4.24"
|
||||
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
|
||||
integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==
|
||||
|
|
@ -6248,6 +6275,38 @@ jsdom@^11.5.1:
|
|||
ws "^5.2.0"
|
||||
xml-name-validator "^3.0.0"
|
||||
|
||||
jsdom@^13.0.0:
|
||||
version "13.0.0"
|
||||
resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-13.0.0.tgz#f1df2411b714a4e08d1bdc343c0a0889c688210f"
|
||||
integrity sha512-Kmq4ASMNkgpY+YufE322EnIKoiz0UWY2DRkKlU7d5YrIW4xiVRhWFrZV1fr6w/ZNxQ50wGAH5gGRzydgnmkkvw==
|
||||
dependencies:
|
||||
abab "^2.0.0"
|
||||
acorn "^6.0.2"
|
||||
acorn-globals "^4.3.0"
|
||||
array-equal "^1.0.0"
|
||||
cssom "^0.3.4"
|
||||
cssstyle "^1.1.1"
|
||||
data-urls "^1.0.1"
|
||||
domexception "^1.0.1"
|
||||
escodegen "^1.11.0"
|
||||
html-encoding-sniffer "^1.0.2"
|
||||
nwsapi "^2.0.9"
|
||||
parse5 "5.1.0"
|
||||
pn "^1.1.0"
|
||||
request "^2.88.0"
|
||||
request-promise-native "^1.0.5"
|
||||
saxes "^3.1.3"
|
||||
symbol-tree "^3.2.2"
|
||||
tough-cookie "^2.4.3"
|
||||
w3c-hr-time "^1.0.1"
|
||||
w3c-xmlserializer "^1.0.0"
|
||||
webidl-conversions "^4.0.2"
|
||||
whatwg-encoding "^1.0.5"
|
||||
whatwg-mimetype "^2.2.0"
|
||||
whatwg-url "^7.0.0"
|
||||
ws "^6.1.0"
|
||||
xml-name-validator "^3.0.0"
|
||||
|
||||
jsesc@^1.3.0:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b"
|
||||
|
|
@ -7407,7 +7466,7 @@ number-is-nan@^1.0.0:
|
|||
resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d"
|
||||
integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=
|
||||
|
||||
nwsapi@^2.0.7:
|
||||
nwsapi@^2.0.7, nwsapi@^2.0.9:
|
||||
version "2.0.9"
|
||||
resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.0.9.tgz#77ac0cdfdcad52b6a1151a84e73254edc33ed016"
|
||||
integrity sha512-nlWFSCTYQcHk/6A9FFnfhKc14c3aFhfdNBXgo8Qgi9QTBu/qg3Ww+Uiz9wMzXd1T8GFxPc2QIHB6Qtf2XFryFQ==
|
||||
|
|
@ -7755,6 +7814,11 @@ parse5@4.0.0:
|
|||
resolved "https://registry.yarnpkg.com/parse5/-/parse5-4.0.0.tgz#6d78656e3da8d78b4ec0b906f7c08ef1dfe3f608"
|
||||
integrity sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA==
|
||||
|
||||
parse5@5.1.0:
|
||||
version "5.1.0"
|
||||
resolved "https://registry.yarnpkg.com/parse5/-/parse5-5.1.0.tgz#c59341c9723f414c452975564c7c00a68d58acd2"
|
||||
integrity sha512-fxNG2sQjHvlVAYmzBZS9YlDp6PTSSDwa98vkD4QgVDDCAo84z5X1t5XyJQ62ImdLXx5NdIIfihey6xpum9/gRQ==
|
||||
|
||||
parseurl@~1.3.2:
|
||||
version "1.3.2"
|
||||
resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.2.tgz#fc289d4ed8993119460c156253262cdc8de65bf3"
|
||||
|
|
@ -9318,7 +9382,7 @@ request@2.87.0:
|
|||
tunnel-agent "^0.6.0"
|
||||
uuid "^3.1.0"
|
||||
|
||||
request@^2.87.0:
|
||||
request@^2.87.0, request@^2.88.0:
|
||||
version "2.88.0"
|
||||
resolved "https://registry.yarnpkg.com/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef"
|
||||
integrity sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==
|
||||
|
|
@ -9579,6 +9643,13 @@ sax@^1.2.4, sax@~1.2.1:
|
|||
resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
|
||||
integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==
|
||||
|
||||
saxes@^3.1.3:
|
||||
version "3.1.3"
|
||||
resolved "https://registry.yarnpkg.com/saxes/-/saxes-3.1.3.tgz#334ab3b802a465ccda96fff9bdefbd505546ffa8"
|
||||
integrity sha512-Nc5DXc5A+m3rUDtkS+vHlBWKT7mCKjJPyia7f8YMW773hsXVv2wEHQZGE0zs4+5PLwz9U5Sbl/94Cnd9vHV7Bg==
|
||||
dependencies:
|
||||
xmlchars "^1.3.1"
|
||||
|
||||
schema-utils@^0.3.0:
|
||||
version "0.3.0"
|
||||
resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-0.3.0.tgz#f5877222ce3e931edae039f17eb3716e7137f8cf"
|
||||
|
|
@ -10466,7 +10537,7 @@ toposort@^1.0.0:
|
|||
resolved "https://registry.yarnpkg.com/toposort/-/toposort-1.0.7.tgz#2e68442d9f64ec720b8cc89e6443ac6caa950029"
|
||||
integrity sha1-LmhELZ9k7HILjMieZEOsbKqVACk=
|
||||
|
||||
tough-cookie@>=2.3.3, tough-cookie@^2.3.4, tough-cookie@~2.4.3:
|
||||
tough-cookie@>=2.3.3, tough-cookie@^2.3.4, tough-cookie@^2.4.3, tough-cookie@~2.4.3:
|
||||
version "2.4.3"
|
||||
resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.4.3.tgz#53f36da3f47783b0925afa06ff9f3b165280f781"
|
||||
integrity sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==
|
||||
|
|
@ -10846,6 +10917,15 @@ w3c-hr-time@^1.0.1:
|
|||
dependencies:
|
||||
browser-process-hrtime "^0.1.2"
|
||||
|
||||
w3c-xmlserializer@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/w3c-xmlserializer/-/w3c-xmlserializer-1.0.0.tgz#d23e20de595b892056f20a359fc2622908d48695"
|
||||
integrity sha512-0et1+9uXYiIRAecx1D5Z1nk60+vimniGdIKl4XjeqkWi6acoHNlXMv1VR5jV+jF4ooeO08oWbYxeAJOcon1oMA==
|
||||
dependencies:
|
||||
domexception "^1.0.1"
|
||||
webidl-conversions "^4.0.2"
|
||||
xml-name-validator "^3.0.0"
|
||||
|
||||
walker@~1.0.5:
|
||||
version "1.0.7"
|
||||
resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.7.tgz#2f7f9b8fd10d677262b18a884e28d19618e028fb"
|
||||
|
|
@ -11007,6 +11087,13 @@ whatwg-encoding@^1.0.1, whatwg-encoding@^1.0.3:
|
|||
dependencies:
|
||||
iconv-lite "0.4.23"
|
||||
|
||||
whatwg-encoding@^1.0.5:
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz#5abacf777c32166a51d085d6b4f3e7d27113ddb0"
|
||||
integrity sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==
|
||||
dependencies:
|
||||
iconv-lite "0.4.24"
|
||||
|
||||
whatwg-fetch@2.0.4:
|
||||
version "2.0.4"
|
||||
resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.4.tgz#dde6a5df315f9d39991aa17621853d720b85566f"
|
||||
|
|
@ -11022,6 +11109,11 @@ whatwg-mimetype@^2.1.0:
|
|||
resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.1.0.tgz#f0f21d76cbba72362eb609dbed2a30cd17fcc7d4"
|
||||
integrity sha512-FKxhYLytBQiUKjkYteN71fAUA3g6KpNXoho1isLiLSB3N1G4F35Q5vUxWfKFhBwi5IWF27VE6WxhrnnC+m0Mew==
|
||||
|
||||
whatwg-mimetype@^2.2.0:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.2.0.tgz#a3d58ef10b76009b042d03e25591ece89b88d171"
|
||||
integrity sha512-5YSO1nMd5D1hY3WzAQV3PzZL83W3YeyR1yW9PcH26Weh1t+Vzh9B6XkDh7aXm83HBZ4nSMvkjvN2H2ySWIvBgw==
|
||||
|
||||
whatwg-url@^6.4.1:
|
||||
version "6.5.0"
|
||||
resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-6.5.0.tgz#f2df02bff176fd65070df74ad5ccbb5a199965a8"
|
||||
|
|
@ -11149,11 +11241,23 @@ ws@^5.2.0:
|
|||
dependencies:
|
||||
async-limiter "~1.0.0"
|
||||
|
||||
ws@^6.1.0:
|
||||
version "6.1.0"
|
||||
resolved "https://registry.yarnpkg.com/ws/-/ws-6.1.0.tgz#119a9dbf92c54e190ec18d10e871d55c95cf9373"
|
||||
integrity sha512-H3dGVdGvW2H8bnYpIDc3u3LH8Wue3Qh+Zto6aXXFzvESkTVT6rAfKR6tR/+coaUvxs8yHtmNV0uioBF62ZGSTg==
|
||||
dependencies:
|
||||
async-limiter "~1.0.0"
|
||||
|
||||
xml-name-validator@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a"
|
||||
integrity sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==
|
||||
|
||||
xmlchars@^1.3.1:
|
||||
version "1.3.1"
|
||||
resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-1.3.1.tgz#1dda035f833dbb4f86a0c28eaa6ca769214793cf"
|
||||
integrity sha512-tGkGJkN8XqCod7OT+EvGYK5Z4SfDQGD30zAa58OcnAa0RRWgzUEK72tkXhsX1FZd+rgnhRxFtmO+ihkp8LHSkw==
|
||||
|
||||
xmlhttprequest@^1.8.0:
|
||||
version "1.8.0"
|
||||
resolved "https://registry.yarnpkg.com/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz#67fe075c5c24fef39f9d65f5f7b7fe75171968fc"
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue