fix some tests
This commit is contained in:
parent
51ea762bce
commit
291d4682e4
|
@ -180,7 +180,12 @@ module.exports = grunt => {
|
||||||
tasks: ['sass'],
|
tasks: ['sass'],
|
||||||
},
|
},
|
||||||
transpile: {
|
transpile: {
|
||||||
files: ['./ts/**/*.ts', './ts/**/*.tsx', './ts/**/**/*.tsx'],
|
files: [
|
||||||
|
'./ts/**/*.ts',
|
||||||
|
'./ts/**/*.tsx',
|
||||||
|
'./ts/**/**/*.tsx',
|
||||||
|
'./test/ts/**.ts',
|
||||||
|
],
|
||||||
tasks: ['exec:transpile'],
|
tasks: ['exec:transpile'],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -7,4 +7,5 @@ export type ConversationControllerType = {
|
||||||
getOrThrow: (id: string) => ConversationModel;
|
getOrThrow: (id: string) => ConversationModel;
|
||||||
getOrCreateAndWait: (id: string, type: string) => Promise<ConversationModel>;
|
getOrCreateAndWait: (id: string, type: string) => Promise<ConversationModel>;
|
||||||
getOrCreate: (id: string, type: string) => Promise<ConversationModel>;
|
getOrCreate: (id: string, type: string) => Promise<ConversationModel>;
|
||||||
|
dangerouslyCreateAndAdd: (any) => any;
|
||||||
};
|
};
|
||||||
|
|
|
@ -487,8 +487,10 @@ describe('Backup', () => {
|
||||||
|
|
||||||
console.log('Backup test: Create models, save to db/disk');
|
console.log('Backup test: Create models, save to db/disk');
|
||||||
const message = await upgradeMessageSchema(messageWithAttachments);
|
const message = await upgradeMessageSchema(messageWithAttachments);
|
||||||
console.log({ message });
|
await window.Signal.Data.saveMessage(message, {
|
||||||
await message.commit();
|
Message: Whisper.Message,
|
||||||
|
forceSave: true,
|
||||||
|
});
|
||||||
|
|
||||||
const conversation = {
|
const conversation = {
|
||||||
active_at: 1524185933350,
|
active_at: 1524185933350,
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
/* global Whisper */
|
/* global Whisper */
|
||||||
|
|
||||||
Whisper.Fixtures = () => {
|
Whisper.Fixtures = () => {
|
||||||
const VERA_ID = '+13016886524'; // nsa
|
const VERA_ID = '0501cd123456789abcdef05123456789abcdef05123456789abcdef05123456789'; // nsa
|
||||||
const NESTOR_ID = '+17034820623'; // cia
|
const NESTOR_ID = '0502cd123456789abcdef05123456789abcdef05123456789abcdef05123456789'; // cia
|
||||||
const MASHA_ID = '+441242221491'; // gchq
|
const MASHA_ID = '0503cd123456789abcdef05123456789abcdef05123456789abcdef05123456789'; // gchq
|
||||||
const FRED_ID = '+14155537400'; // fbi sf
|
const FRED_ID = '0504cd123456789abcdef05123456789abcdef05123456789abcdef05123456789'; // fbi sf
|
||||||
const MICHEL_ID = '+12024561111'; // twh
|
const MICHEL_ID = '0505cd123456789abcdef05123456789abcdef05123456789abcdef05123456789'; // twh
|
||||||
|
|
||||||
const now = Date.now();
|
const now = Date.now();
|
||||||
const conversationCollection = new Whisper.ConversationCollection([
|
const conversationCollection = new Whisper.ConversationCollection([
|
||||||
|
@ -172,7 +172,7 @@ Whisper.Fixtures = () => {
|
||||||
type: 'group',
|
type: 'group',
|
||||||
active_at: now - 100000,
|
active_at: now - 100000,
|
||||||
timestamp: now - 100000,
|
timestamp: now - 100000,
|
||||||
id: 'group1',
|
id: '05abcd123456789abcdef05123456789abcdef05123456789abcdef05123456789',
|
||||||
lastMessage: 'See you all there!',
|
lastMessage: 'See you all there!',
|
||||||
members: [MICHEL_ID, FRED_ID, NESTOR_ID],
|
members: [MICHEL_ID, FRED_ID, NESTOR_ID],
|
||||||
});
|
});
|
||||||
|
|
|
@ -9,7 +9,7 @@ describe('Fixtures', () => {
|
||||||
|
|
||||||
await clearDatabase();
|
await clearDatabase();
|
||||||
await textsecure.storage.user.setNumberAndDeviceId(
|
await textsecure.storage.user.setNumberAndDeviceId(
|
||||||
'+17015552000',
|
'05123456789abcdef05123456789abcdef05123456789abcdef05123456789abcd',
|
||||||
2,
|
2,
|
||||||
'testDevice'
|
'testDevice'
|
||||||
);
|
);
|
||||||
|
@ -27,12 +27,10 @@ describe('Fixtures', () => {
|
||||||
await ConversationController.load();
|
await ConversationController.load();
|
||||||
|
|
||||||
let view = new Whisper.InboxView({ window });
|
let view = new Whisper.InboxView({ window });
|
||||||
view.onEmpty();
|
|
||||||
view.$el.prependTo($('#render-light-theme'));
|
view.$el.prependTo($('#render-light-theme'));
|
||||||
|
|
||||||
view = new Whisper.InboxView({ window });
|
view = new Whisper.InboxView({ window });
|
||||||
view.$el.removeClass('light-theme').addClass('dark-theme');
|
view.$el.removeClass('light-theme').addClass('dark-theme');
|
||||||
view.onEmpty();
|
|
||||||
view.$el.prependTo($('#render-dark-theme'));
|
view.$el.prependTo($('#render-dark-theme'));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -19,8 +19,8 @@
|
||||||
|
|
||||||
<script type="text/x-tmpl-mustache" id="app-loading-screen">
|
<script type="text/x-tmpl-mustache" id="app-loading-screen">
|
||||||
<div class="content session-full-logo">
|
<div class="content session-full-logo">
|
||||||
<img src="images/session/brand.svg" class="session-brand-logo" />
|
<img src="../images/session/brand.svg" class="session-brand-logo" />
|
||||||
<img src="images/session/session-text.svg" class="session-text-logo" />
|
<img src="../images/session/session-text.svg" class="session-text-logo" />
|
||||||
</div>
|
</div>
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -1,79 +0,0 @@
|
||||||
/* global ConversationController, libsignal, SignalProtocolStore, Whisper */
|
|
||||||
|
|
||||||
describe('KeyChangeListener', () => {
|
|
||||||
const phoneNumberWithKeyChange = '+13016886524'; // nsa
|
|
||||||
const address = new libsignal.SignalProtocolAddress(
|
|
||||||
phoneNumberWithKeyChange,
|
|
||||||
1
|
|
||||||
);
|
|
||||||
const oldKey = libsignal.crypto.getRandomBytes(33);
|
|
||||||
const newKey = libsignal.crypto.getRandomBytes(33);
|
|
||||||
let store;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
store = new SignalProtocolStore();
|
|
||||||
await store.hydrateCaches();
|
|
||||||
Whisper.KeyChangeListener.init(store);
|
|
||||||
return store.saveIdentity(address.toString(), oldKey);
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
return store.removeIdentityKey(phoneNumberWithKeyChange);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('When we have a conversation with this contact', () => {
|
|
||||||
let convo;
|
|
||||||
before(async () => {
|
|
||||||
convo = ConversationController.dangerouslyCreateAndAdd({
|
|
||||||
id: phoneNumberWithKeyChange,
|
|
||||||
type: 'private',
|
|
||||||
});
|
|
||||||
await window.Signal.Data.saveConversation(convo.attributes, {
|
|
||||||
Conversation: Whisper.Conversation,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
after(async () => {
|
|
||||||
await convo.destroyMessages();
|
|
||||||
await window.Signal.Data.saveConversation(convo.id);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('generates a key change notice in the private conversation with this contact', done => {
|
|
||||||
convo.once('newmessage', async () => {
|
|
||||||
await convo.fetchMessages();
|
|
||||||
const message = convo.messageCollection.at(0);
|
|
||||||
assert.strictEqual(message.get('type'), 'keychange');
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
store.saveIdentity(address.toString(), newKey);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('When we have a group with this contact', () => {
|
|
||||||
let convo;
|
|
||||||
before(async () => {
|
|
||||||
convo = ConversationController.dangerouslyCreateAndAdd({
|
|
||||||
id: 'groupId',
|
|
||||||
type: 'group',
|
|
||||||
members: [phoneNumberWithKeyChange],
|
|
||||||
});
|
|
||||||
await window.Signal.Data.saveConversation(convo.attributes, {
|
|
||||||
Conversation: Whisper.Conversation,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
after(async () => {
|
|
||||||
await convo.destroyMessages();
|
|
||||||
await window.Signal.Data.saveConversation(convo.id);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('generates a key change notice in the group conversation with this contact', done => {
|
|
||||||
convo.once('newmessage', async () => {
|
|
||||||
await convo.fetchMessages();
|
|
||||||
const message = convo.messageCollection.at(0);
|
|
||||||
assert.strictEqual(message.get('type'), 'keychange');
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
store.saveIdentity(address.toString(), newKey);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,326 +0,0 @@
|
||||||
const { assert } = require('chai');
|
|
||||||
|
|
||||||
const {
|
|
||||||
findLinks,
|
|
||||||
getTitleMetaTag,
|
|
||||||
getImageMetaTag,
|
|
||||||
isLinkInWhitelist,
|
|
||||||
isLinkSneaky,
|
|
||||||
} = require('../../js/modules/link_previews');
|
|
||||||
|
|
||||||
describe('Link previews', () => {
|
|
||||||
describe('#isLinkInWhitelist', () => {
|
|
||||||
it('returns true for valid links', () => {
|
|
||||||
assert.strictEqual(isLinkInWhitelist('https://youtube.com/blah'), true);
|
|
||||||
assert.strictEqual(
|
|
||||||
isLinkInWhitelist('https://www.youtube.com/blah'),
|
|
||||||
true
|
|
||||||
);
|
|
||||||
assert.strictEqual(isLinkInWhitelist('https://m.youtube.com/blah'), true);
|
|
||||||
assert.strictEqual(isLinkInWhitelist('https://youtu.be/blah'), true);
|
|
||||||
assert.strictEqual(isLinkInWhitelist('https://reddit.com/blah'), true);
|
|
||||||
assert.strictEqual(
|
|
||||||
isLinkInWhitelist('https://www.reddit.com/blah'),
|
|
||||||
true
|
|
||||||
);
|
|
||||||
assert.strictEqual(isLinkInWhitelist('https://m.reddit.com/blah'), true);
|
|
||||||
assert.strictEqual(isLinkInWhitelist('https://imgur.com/blah'), true);
|
|
||||||
assert.strictEqual(isLinkInWhitelist('https://www.imgur.com/blah'), true);
|
|
||||||
assert.strictEqual(isLinkInWhitelist('https://m.imgur.com/blah'), true);
|
|
||||||
assert.strictEqual(isLinkInWhitelist('https://instagram.com/blah'), true);
|
|
||||||
assert.strictEqual(
|
|
||||||
isLinkInWhitelist('https://www.instagram.com/blah'),
|
|
||||||
true
|
|
||||||
);
|
|
||||||
assert.strictEqual(
|
|
||||||
isLinkInWhitelist('https://m.instagram.com/blah'),
|
|
||||||
true
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns false for subdomains', () => {
|
|
||||||
assert.strictEqual(
|
|
||||||
isLinkInWhitelist('https://any.subdomain.youtube.com/blah'),
|
|
||||||
false
|
|
||||||
);
|
|
||||||
assert.strictEqual(
|
|
||||||
isLinkInWhitelist('https://any.subdomain.instagram.com/blah'),
|
|
||||||
false
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns false for http links', () => {
|
|
||||||
assert.strictEqual(isLinkInWhitelist('http://instagram.com/blah'), false);
|
|
||||||
assert.strictEqual(isLinkInWhitelist('http://youtube.com/blah'), false);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns false for links with no protocol', () => {
|
|
||||||
assert.strictEqual(isLinkInWhitelist('instagram.com/blah'), false);
|
|
||||||
assert.strictEqual(isLinkInWhitelist('youtube.com/blah'), false);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns false for link to root path', () => {
|
|
||||||
assert.strictEqual(isLinkInWhitelist('https://instagram.com'), false);
|
|
||||||
assert.strictEqual(isLinkInWhitelist('https://youtube.com'), false);
|
|
||||||
|
|
||||||
assert.strictEqual(isLinkInWhitelist('https://instagram.com/'), false);
|
|
||||||
assert.strictEqual(isLinkInWhitelist('https://youtube.com/'), false);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns false for other well-known sites', () => {
|
|
||||||
assert.strictEqual(isLinkInWhitelist('https://facebook.com/blah'), false);
|
|
||||||
assert.strictEqual(isLinkInWhitelist('https://twitter.com/blah'), false);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns false for links that look like our target links', () => {
|
|
||||||
assert.strictEqual(
|
|
||||||
isLinkInWhitelist('https://evil.site.com/.instagram.com/blah'),
|
|
||||||
false
|
|
||||||
);
|
|
||||||
assert.strictEqual(
|
|
||||||
isLinkInWhitelist('https://evil.site.com/.instagram.com/blah'),
|
|
||||||
false
|
|
||||||
);
|
|
||||||
assert.strictEqual(
|
|
||||||
isLinkInWhitelist('https://sinstagram.com/blah'),
|
|
||||||
false
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('#_getMetaTag', () => {
|
|
||||||
it('returns html-decoded tag contents from Youtube', () => {
|
|
||||||
const youtube = `
|
|
||||||
<meta property="og:site_name" content="YouTube">
|
|
||||||
<meta property="og:url" content="https://www.youtube.com/watch?v=tP-Ipsat90c">
|
|
||||||
<meta property="og:type" content="video.other">
|
|
||||||
<meta property="og:title" content="Randomness is Random - Numberphile">
|
|
||||||
<meta property="og:image" content="https://i.ytimg.com/vi/tP-Ipsat90c/maxresdefault.jpg">
|
|
||||||
`;
|
|
||||||
|
|
||||||
assert.strictEqual(
|
|
||||||
'Randomness is Random - Numberphile',
|
|
||||||
getTitleMetaTag(youtube)
|
|
||||||
);
|
|
||||||
assert.strictEqual(
|
|
||||||
'https://i.ytimg.com/vi/tP-Ipsat90c/maxresdefault.jpg',
|
|
||||||
getImageMetaTag(youtube)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns html-decoded tag contents from Instagram', () => {
|
|
||||||
const instagram = `
|
|
||||||
<meta property="og:site_name" content="Instagram" />
|
|
||||||
<meta property="og:url" content="https://www.instagram.com/p/BrgpsUjF9Jo/" />
|
|
||||||
<meta property="og:type" content="instapp:photo" />
|
|
||||||
<meta property="og:title" content="Walter "MFPallytime" on Instagram: “Lol gg”" />
|
|
||||||
<meta property="og:description" content="632 Likes, 56 Comments - Walter "MFPallytime" (@mfpallytime) on Instagram: “Lol gg ”" />
|
|
||||||
<meta property="og:image" content="https://scontent-lax3-1.cdninstagram.com/vp/1c69aa381c2201720c29a6c28de42ffd/5CD49B5B/t51.2885-15/e35/47690175_2275988962411653_1145978227188801192_n.jpg?_nc_ht=scontent-lax3-1.cdninstagram.com" />
|
|
||||||
`;
|
|
||||||
|
|
||||||
assert.strictEqual(
|
|
||||||
'Walter "MFPallytime" on Instagram: “Lol gg”',
|
|
||||||
getTitleMetaTag(instagram)
|
|
||||||
);
|
|
||||||
assert.strictEqual(
|
|
||||||
'https://scontent-lax3-1.cdninstagram.com/vp/1c69aa381c2201720c29a6c28de42ffd/5CD49B5B/t51.2885-15/e35/47690175_2275988962411653_1145978227188801192_n.jpg?_nc_ht=scontent-lax3-1.cdninstagram.com',
|
|
||||||
getImageMetaTag(instagram)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns html-decoded tag contents from Imgur', () => {
|
|
||||||
const imgur = `
|
|
||||||
<meta property="og:site_name" content="Imgur">
|
|
||||||
<meta property="og:url" content="https://imgur.com/gallery/KFCL8fm">
|
|
||||||
<meta property="og:type" content="article">
|
|
||||||
<meta property="og:title" content=" ">
|
|
||||||
<meta property="og:description" content="13246 views and 482 votes on Imgur">
|
|
||||||
<meta property="og:image" content="https://i.imgur.com/Y3wjlwY.jpg?fb">
|
|
||||||
<meta property="og:image:width" content="600">
|
|
||||||
<meta property="og:image:height" content="315">
|
|
||||||
`;
|
|
||||||
|
|
||||||
assert.strictEqual('', getTitleMetaTag(imgur));
|
|
||||||
assert.strictEqual(
|
|
||||||
'https://i.imgur.com/Y3wjlwY.jpg?fb',
|
|
||||||
getImageMetaTag(imgur)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns html-decoded tag contents from Giphy', () => {
|
|
||||||
const giphy = `
|
|
||||||
<meta property="og:site_name" content="GIPHY">
|
|
||||||
<meta property="og:url" content="https://media.giphy.com/media/3o7qE8mq5bT9FQj7j2/giphy.gif">
|
|
||||||
<meta property="og:type" content="video.other">
|
|
||||||
<meta property="og:title" content="I Cant Hear You Kobe Bryant GIF - Find & Share on GIPHY">
|
|
||||||
<meta property="og:description" content="Discover & share this Kobe GIF with everyone you know. GIPHY is how you search, share, discover, and create GIFs.">
|
|
||||||
<meta property="og:image" content="https://media.giphy.com/media/3o7qE8mq5bT9FQj7j2/giphy.gif">
|
|
||||||
<meta property="og:image:width" content="480">
|
|
||||||
<meta property="og:image:height" content="262">
|
|
||||||
`;
|
|
||||||
|
|
||||||
assert.strictEqual(
|
|
||||||
'I Cant Hear You Kobe Bryant GIF - Find & Share on GIPHY',
|
|
||||||
getTitleMetaTag(giphy)
|
|
||||||
);
|
|
||||||
assert.strictEqual(
|
|
||||||
'https://media.giphy.com/media/3o7qE8mq5bT9FQj7j2/giphy.gif',
|
|
||||||
getImageMetaTag(giphy)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns html-decoded tag contents from Tenor', () => {
|
|
||||||
const tenor = `
|
|
||||||
<meta class="dynamic" property="og:site_name" content="Tenor" >
|
|
||||||
<meta class="dynamic" property="og:url" content="https://media1.tenor.com/images/3772949a5b042e626d259f313fd1e9b8/tenor.gif?itemid=14834517">
|
|
||||||
<meta class="dynamic" property="og:type" content="video.other">
|
|
||||||
<meta class="dynamic" property="og:title" content="Hopping Jumping GIF - Hopping Jumping Bird - Discover & Share GIFs">
|
|
||||||
<meta class="dynamic" property="og:description" content="Click to view the GIF">
|
|
||||||
<meta class="dynamic" property="og:image" content="https://media1.tenor.com/images/3772949a5b042e626d259f313fd1e9b8/tenor.gif?itemid=14834517">
|
|
||||||
<meta class="dynamic" property="og:image:width" content="498">
|
|
||||||
<meta class="dynamic" property="og:image:height" content="435">
|
|
||||||
`;
|
|
||||||
|
|
||||||
assert.strictEqual(
|
|
||||||
'Hopping Jumping GIF - Hopping Jumping Bird - Discover & Share GIFs',
|
|
||||||
getTitleMetaTag(tenor)
|
|
||||||
);
|
|
||||||
assert.strictEqual(
|
|
||||||
'https://media1.tenor.com/images/3772949a5b042e626d259f313fd1e9b8/tenor.gif?itemid=14834517',
|
|
||||||
getImageMetaTag(tenor)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns only the first tag', () => {
|
|
||||||
const html = `
|
|
||||||
<meta property="og:title" content="First Second Third"><meta property="og:title" content="Fourth Fifth Sixth">
|
|
||||||
`;
|
|
||||||
|
|
||||||
assert.strictEqual('First Second Third', getTitleMetaTag(html));
|
|
||||||
});
|
|
||||||
|
|
||||||
it('handles a newline in attribute value', () => {
|
|
||||||
const html = `
|
|
||||||
<meta property="og:title" content="First thing\r\nSecond thing\nThird thing">
|
|
||||||
`;
|
|
||||||
|
|
||||||
assert.strictEqual(
|
|
||||||
'First thing\r\nSecond thing\nThird thing',
|
|
||||||
getTitleMetaTag(html)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('converts image url protocol http to https', () => {
|
|
||||||
const html = `
|
|
||||||
<meta property="og:image" content="http://giphygifs.s3.amazonaws.com/media/APcFiiTrG0x2/200.gif">
|
|
||||||
`;
|
|
||||||
|
|
||||||
assert.strictEqual(
|
|
||||||
'https://giphygifs.s3.amazonaws.com/media/APcFiiTrG0x2/200.gif',
|
|
||||||
getImageMetaTag(html)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('#findLinks', () => {
|
|
||||||
it('returns all links if no caretLocation is provided', () => {
|
|
||||||
const text =
|
|
||||||
'Check out this link: https://github.com/signalapp/Signal-Desktop\nAnd this one too: https://github.com/signalapp/Signal-Android';
|
|
||||||
|
|
||||||
const expected = [
|
|
||||||
'https://github.com/signalapp/Signal-Desktop',
|
|
||||||
'https://github.com/signalapp/Signal-Android',
|
|
||||||
];
|
|
||||||
|
|
||||||
const actual = findLinks(text);
|
|
||||||
assert.deepEqual(expected, actual);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('includes all links if cursor is not in a link', () => {
|
|
||||||
const text =
|
|
||||||
'Check out this link: https://github.com/signalapp/Signal-Desktop\nAnd this one too: https://github.com/signalapp/Signal-Android';
|
|
||||||
const caretLocation = 10;
|
|
||||||
|
|
||||||
const expected = [
|
|
||||||
'https://github.com/signalapp/Signal-Desktop',
|
|
||||||
'https://github.com/signalapp/Signal-Android',
|
|
||||||
];
|
|
||||||
|
|
||||||
const actual = findLinks(text, caretLocation);
|
|
||||||
assert.deepEqual(expected, actual);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('excludes a link not at the end if the caret is inside of it', () => {
|
|
||||||
const text =
|
|
||||||
'Check out this link: https://github.com/signalapp/Signal-Desktop\nAnd this one too: https://github.com/signalapp/Signal-Android';
|
|
||||||
const caretLocation = 30;
|
|
||||||
|
|
||||||
const expected = ['https://github.com/signalapp/Signal-Android'];
|
|
||||||
|
|
||||||
const actual = findLinks(text, caretLocation);
|
|
||||||
assert.deepEqual(expected, actual);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('excludes a link not at the end if the caret is at its end', () => {
|
|
||||||
const text =
|
|
||||||
'Check out this link: https://github.com/signalapp/Signal-Desktop\nAnd this one too: https://github.com/signalapp/Signal-Android';
|
|
||||||
const caretLocation = 64;
|
|
||||||
|
|
||||||
const expected = ['https://github.com/signalapp/Signal-Android'];
|
|
||||||
|
|
||||||
const actual = findLinks(text, caretLocation);
|
|
||||||
assert.deepEqual(expected, actual);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('excludes a link at the end of the caret is inside of it', () => {
|
|
||||||
const text =
|
|
||||||
'Check out this link: https://github.com/signalapp/Signal-Desktop\nAnd this one too: https://github.com/signalapp/Signal-Android';
|
|
||||||
const caretLocation = 100;
|
|
||||||
|
|
||||||
const expected = ['https://github.com/signalapp/Signal-Desktop'];
|
|
||||||
|
|
||||||
const actual = findLinks(text, caretLocation);
|
|
||||||
assert.deepEqual(expected, actual);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('includes link at the end if cursor is at its end', () => {
|
|
||||||
const text =
|
|
||||||
'Check out this link: https://github.com/signalapp/Signal-Desktop\nAnd this one too: https://github.com/signalapp/Signal-Android';
|
|
||||||
const caretLocation = text.length;
|
|
||||||
|
|
||||||
const expected = [
|
|
||||||
'https://github.com/signalapp/Signal-Desktop',
|
|
||||||
'https://github.com/signalapp/Signal-Android',
|
|
||||||
];
|
|
||||||
|
|
||||||
const actual = findLinks(text, caretLocation);
|
|
||||||
assert.deepEqual(expected, actual);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('#isLinkSneaky', () => {
|
|
||||||
it('returns false for all-latin domain', () => {
|
|
||||||
const link = 'https://www.amazon.com';
|
|
||||||
const actual = isLinkSneaky(link);
|
|
||||||
assert.strictEqual(actual, false);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns true for Latin + Cyrillic domain', () => {
|
|
||||||
const link = 'https://www.aмazon.com';
|
|
||||||
const actual = isLinkSneaky(link);
|
|
||||||
assert.strictEqual(actual, true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns true for Latin + Greek domain', () => {
|
|
||||||
const link = 'https://www.αpple.com';
|
|
||||||
const actual = isLinkSneaky(link);
|
|
||||||
assert.strictEqual(actual, true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns true for Latin + High Greek domain', () => {
|
|
||||||
const link = `https://www.apple${String.fromCodePoint(0x101a0)}.com`;
|
|
||||||
const actual = isLinkSneaky(link);
|
|
||||||
assert.strictEqual(actual, true);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -50,7 +50,12 @@ export class ContactListItem extends React.Component<Props> {
|
||||||
const profileElement =
|
const profileElement =
|
||||||
!isMe && profileName && !name ? (
|
!isMe && profileName && !name ? (
|
||||||
<span className="module-contact-list-item__text__profile-name">
|
<span className="module-contact-list-item__text__profile-name">
|
||||||
~<Emojify text={profileName} i18n={i18n} />
|
~
|
||||||
|
<Emojify
|
||||||
|
text={profileName}
|
||||||
|
i18n={i18n}
|
||||||
|
key={`emojify-list-item-${phoneNumber}`}
|
||||||
|
/>
|
||||||
</span>
|
</span>
|
||||||
) : null;
|
) : null;
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,6 @@ import { Avatar } from '../Avatar';
|
||||||
import { LocalizerType } from '../../types/Util';
|
import { LocalizerType } from '../../types/Util';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
SessionIcon,
|
|
||||||
SessionIconButton,
|
SessionIconButton,
|
||||||
SessionIconSize,
|
SessionIconSize,
|
||||||
SessionIconType,
|
SessionIconType,
|
||||||
|
@ -89,7 +88,6 @@ interface Props {
|
||||||
onAvatarClick?: (userPubKey: string) => void;
|
onAvatarClick?: (userPubKey: string) => void;
|
||||||
onUpdateGroupName: () => void;
|
onUpdateGroupName: () => void;
|
||||||
|
|
||||||
i18n: LocalizerType;
|
|
||||||
memberAvatars?: Array<ConversationAvatar>; // this is added by usingClosedConversationDetails
|
memberAvatars?: Array<ConversationAvatar>; // this is added by usingClosedConversationDetails
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,7 +119,6 @@ class ConversationHeader extends React.Component<Props> {
|
||||||
public renderTitle() {
|
public renderTitle() {
|
||||||
const {
|
const {
|
||||||
phoneNumber,
|
phoneNumber,
|
||||||
i18n,
|
|
||||||
profileName,
|
profileName,
|
||||||
isGroup,
|
isGroup,
|
||||||
isPublic,
|
isPublic,
|
||||||
|
@ -132,6 +129,7 @@ class ConversationHeader extends React.Component<Props> {
|
||||||
isKickedFromGroup,
|
isKickedFromGroup,
|
||||||
name,
|
name,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
const { i18n } = window;
|
||||||
|
|
||||||
if (isMe) {
|
if (isMe) {
|
||||||
return (
|
return (
|
||||||
|
@ -232,12 +230,9 @@ class ConversationHeader extends React.Component<Props> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public renderSelectionOverlay() {
|
public renderSelectionOverlay() {
|
||||||
const {
|
const { onDeleteSelectedMessages, onCloseOverlay, isPublic } = this.props;
|
||||||
onDeleteSelectedMessages,
|
const { i18n } = window;
|
||||||
onCloseOverlay,
|
|
||||||
isPublic,
|
|
||||||
i18n,
|
|
||||||
} = this.props;
|
|
||||||
const isServerDeletable = isPublic;
|
const isServerDeletable = isPublic;
|
||||||
const deleteMessageButtonText = i18n(
|
const deleteMessageButtonText = i18n(
|
||||||
isServerDeletable ? 'deleteForEveryone' : 'delete'
|
isServerDeletable ? 'deleteForEveryone' : 'delete'
|
||||||
|
@ -266,7 +261,7 @@ class ConversationHeader extends React.Component<Props> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public render() {
|
public render() {
|
||||||
const { id, isKickedFromGroup, selectionMode } = this.props;
|
const { isKickedFromGroup, selectionMode } = this.props;
|
||||||
const triggerId = 'conversation-header';
|
const triggerId = 'conversation-header';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -86,9 +86,9 @@ export class Emojify extends React.Component<Props> {
|
||||||
const emojiText = match[0] ?? match[1];
|
const emojiText = match[0] ?? match[1];
|
||||||
|
|
||||||
results.push(
|
results.push(
|
||||||
<span style={style}>
|
<span style={style} key={count++}>
|
||||||
<Twemoji
|
<Twemoji
|
||||||
key={count++}
|
key={count}
|
||||||
text={emojiText}
|
text={emojiText}
|
||||||
options={
|
options={
|
||||||
{
|
{
|
||||||
|
|
|
@ -72,8 +72,9 @@ class ActionsPanelPrivate extends React.Component<Props> {
|
||||||
|
|
||||||
if (type === SectionType.Profile) {
|
if (type === SectionType.Profile) {
|
||||||
const ourPrimary = window.storage.get('primaryDevicePubKey');
|
const ourPrimary = window.storage.get('primaryDevicePubKey');
|
||||||
const conversation = window.ConversationController.getOrThrow(ourPrimary);
|
const conversation = window.ConversationController.get(ourPrimary);
|
||||||
const profile = conversation.getLokiProfile();
|
|
||||||
|
const profile = conversation?.getLokiProfile();
|
||||||
const userName = (profile && profile.displayName) || ourPrimary;
|
const userName = (profile && profile.displayName) || ourPrimary;
|
||||||
return (
|
return (
|
||||||
<Avatar
|
<Avatar
|
||||||
|
@ -136,7 +137,7 @@ class ActionsPanelPrivate extends React.Component<Props> {
|
||||||
<div className="module-left-pane__sections-container">
|
<div className="module-left-pane__sections-container">
|
||||||
<this.Section
|
<this.Section
|
||||||
type={SectionType.Profile}
|
type={SectionType.Profile}
|
||||||
avatarPath={this.props.ourPrimaryConversation.avatarPath}
|
avatarPath={this.props.ourPrimaryConversation?.avatarPath}
|
||||||
isSelected={isProfilePageSelected}
|
isSelected={isProfilePageSelected}
|
||||||
onSelect={this.handleSectionSelect}
|
onSelect={this.handleSectionSelect}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -412,7 +412,6 @@ export class SessionConversation extends React.Component<Props, State> {
|
||||||
const members = conversation.get('members') || [];
|
const members = conversation.get('members') || [];
|
||||||
|
|
||||||
const headerProps = {
|
const headerProps = {
|
||||||
i18n: window.i18n,
|
|
||||||
id: conversation.id,
|
id: conversation.id,
|
||||||
name: conversation.getName(),
|
name: conversation.getName(),
|
||||||
phoneNumber: conversation.getNumber(),
|
phoneNumber: conversation.getNumber(),
|
||||||
|
|
|
@ -26,6 +26,7 @@ declare global {
|
||||||
interface Window {
|
interface Window {
|
||||||
CONSTANTS: any;
|
CONSTANTS: any;
|
||||||
ConversationController: ConversationControllerType;
|
ConversationController: ConversationControllerType;
|
||||||
|
SignalProtocolStore: any;
|
||||||
Events: any;
|
Events: any;
|
||||||
Lodash: any;
|
Lodash: any;
|
||||||
LokiAppDotNetServerAPI: any;
|
LokiAppDotNetServerAPI: any;
|
||||||
|
|
Loading…
Reference in New Issue