@ -0,0 +1,33 @@ | |||
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||
exports[`<Avatar /> Autoplay renders a animated avatar 1`] = ` | |||
<div | |||
className="account__avatar" | |||
onMouseEnter={[Function]} | |||
onMouseLeave={[Function]} | |||
style={ | |||
Object { | |||
"backgroundImage": "url(/animated/alice.gif)", | |||
"backgroundSize": "100px 100px", | |||
"height": "100px", | |||
"width": "100px", | |||
} | |||
} | |||
/> | |||
`; | |||
exports[`<Avatar /> Still renders a still avatar 1`] = ` | |||
<div | |||
className="account__avatar" | |||
onMouseEnter={[Function]} | |||
onMouseLeave={[Function]} | |||
style={ | |||
Object { | |||
"backgroundImage": "url(/static/alice.jpg)", | |||
"backgroundSize": "100px 100px", | |||
"height": "100px", | |||
"width": "100px", | |||
} | |||
} | |||
/> | |||
`; |
@ -0,0 +1,24 @@ | |||
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||
exports[`<AvatarOverlay renders a overlay avatar 1`] = ` | |||
<div | |||
className="account__avatar-overlay" | |||
> | |||
<div | |||
className="account__avatar-overlay-base" | |||
style={ | |||
Object { | |||
"backgroundImage": "url(/static/alice.jpg)", | |||
} | |||
} | |||
/> | |||
<div | |||
className="account__avatar-overlay-overlay" | |||
style={ | |||
Object { | |||
"backgroundImage": "url(/static/eve.jpg)", | |||
} | |||
} | |||
/> | |||
</div> | |||
`; |
@ -0,0 +1,114 @@ | |||
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||
exports[`<Button /> adds class "button-secondary" if props.secondary given 1`] = ` | |||
<button | |||
className="button button-secondary" | |||
disabled={undefined} | |||
onClick={[Function]} | |||
style={ | |||
Object { | |||
"height": "36px", | |||
"lineHeight": "36px", | |||
"padding": "0 16px", | |||
} | |||
} | |||
/> | |||
`; | |||
exports[`<Button /> renders a button element 1`] = ` | |||
<button | |||
className="button" | |||
disabled={undefined} | |||
onClick={[Function]} | |||
style={ | |||
Object { | |||
"height": "36px", | |||
"lineHeight": "36px", | |||
"padding": "0 16px", | |||
} | |||
} | |||
/> | |||
`; | |||
exports[`<Button /> renders a disabled attribute if props.disabled given 1`] = ` | |||
<button | |||
className="button" | |||
disabled={true} | |||
onClick={[Function]} | |||
style={ | |||
Object { | |||
"height": "36px", | |||
"lineHeight": "36px", | |||
"padding": "0 16px", | |||
} | |||
} | |||
/> | |||
`; | |||
exports[`<Button /> renders class="button--block" if props.block given 1`] = ` | |||
<button | |||
className="button button--block" | |||
disabled={undefined} | |||
onClick={[Function]} | |||
style={ | |||
Object { | |||
"height": "36px", | |||
"lineHeight": "36px", | |||
"padding": "0 16px", | |||
} | |||
} | |||
/> | |||
`; | |||
exports[`<Button /> renders the children 1`] = ` | |||
<button | |||
className="button" | |||
disabled={undefined} | |||
onClick={[Function]} | |||
style={ | |||
Object { | |||
"height": "36px", | |||
"lineHeight": "36px", | |||
"padding": "0 16px", | |||
} | |||
} | |||
> | |||
<p> | |||
children | |||
</p> | |||
</button> | |||
`; | |||
exports[`<Button /> renders the given text 1`] = ` | |||
<button | |||
className="button" | |||
disabled={undefined} | |||
onClick={[Function]} | |||
style={ | |||
Object { | |||
"height": "36px", | |||
"lineHeight": "36px", | |||
"padding": "0 16px", | |||
} | |||
} | |||
> | |||
foo | |||
</button> | |||
`; | |||
exports[`<Button /> renders the props.text instead of children 1`] = ` | |||
<button | |||
className="button" | |||
disabled={undefined} | |||
onClick={[Function]} | |||
style={ | |||
Object { | |||
"height": "36px", | |||
"lineHeight": "36px", | |||
"padding": "0 16px", | |||
} | |||
} | |||
> | |||
foo | |||
</button> | |||
`; |
@ -0,0 +1,23 @@ | |||
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||
exports[`<DisplayName /> renders display name + account name 1`] = ` | |||
<span | |||
className="display-name" | |||
> | |||
<strong | |||
className="display-name__html" | |||
dangerouslySetInnerHTML={ | |||
Object { | |||
"__html": "<p>Foo</p>", | |||
} | |||
} | |||
/> | |||
<span | |||
className="display-name__account" | |||
> | |||
@ | |||
bar@baz | |||
</span> | |||
</span> | |||
`; |
@ -0,0 +1,36 @@ | |||
import React from 'react'; | |||
import renderer from 'react-test-renderer'; | |||
import { fromJS } from 'immutable'; | |||
import Avatar from '../avatar'; | |||
describe('<Avatar />', () => { | |||
const account = fromJS({ | |||
username: 'alice', | |||
acct: 'alice', | |||
display_name: 'Alice', | |||
avatar: '/animated/alice.gif', | |||
avatar_static: '/static/alice.jpg', | |||
}); | |||
const size = 100; | |||
describe('Autoplay', () => { | |||
it('renders a animated avatar', () => { | |||
const component = renderer.create(<Avatar account={account} animate size={size} />); | |||
const tree = component.toJSON(); | |||
expect(tree).toMatchSnapshot(); | |||
}); | |||
}); | |||
describe('Still', () => { | |||
it('renders a still avatar', () => { | |||
const component = renderer.create(<Avatar account={account} size={size} />); | |||
const tree = component.toJSON(); | |||
expect(tree).toMatchSnapshot(); | |||
}); | |||
}); | |||
// TODO add autoplay test if possible | |||
}); |
@ -0,0 +1,29 @@ | |||
import React from 'react'; | |||
import renderer from 'react-test-renderer'; | |||
import { fromJS } from 'immutable'; | |||
import AvatarOverlay from '../avatar_overlay'; | |||
describe('<AvatarOverlay', () => { | |||
const account = fromJS({ | |||
username: 'alice', | |||
acct: 'alice', | |||
display_name: 'Alice', | |||
avatar: '/animated/alice.gif', | |||
avatar_static: '/static/alice.jpg', | |||
}); | |||
const friend = fromJS({ | |||
username: 'eve', | |||
acct: 'eve@blackhat.lair', | |||
display_name: 'Evelyn', | |||
avatar: '/animated/eve.gif', | |||
avatar_static: '/static/eve.jpg', | |||
}); | |||
it('renders a overlay avatar', () => { | |||
const component = renderer.create(<AvatarOverlay account={account} friend={friend} />); | |||
const tree = component.toJSON(); | |||
expect(tree).toMatchSnapshot(); | |||
}); | |||
}); |
@ -0,0 +1,75 @@ | |||
import { shallow } from 'enzyme'; | |||
import React from 'react'; | |||
import renderer from 'react-test-renderer'; | |||
import Button from '../button'; | |||
describe('<Button />', () => { | |||
it('renders a button element', () => { | |||
const component = renderer.create(<Button />); | |||
const tree = component.toJSON(); | |||
expect(tree).toMatchSnapshot(); | |||
}); | |||
it('renders the given text', () => { | |||
const text = 'foo'; | |||
const component = renderer.create(<Button text={text} />); | |||
const tree = component.toJSON(); | |||
expect(tree).toMatchSnapshot(); | |||
}); | |||
it('handles click events using the given handler', () => { | |||
const handler = jest.fn(); | |||
const button = shallow(<Button onClick={handler} />); | |||
button.find('button').simulate('click'); | |||
expect(handler.mock.calls.length).toEqual(1); | |||
}); | |||
it('does not handle click events if props.disabled given', () => { | |||
const handler = jest.fn(); | |||
const button = shallow(<Button onClick={handler} disabled />); | |||
button.find('button').simulate('click'); | |||
expect(handler.mock.calls.length).toEqual(0); | |||
}); | |||
it('renders a disabled attribute if props.disabled given', () => { | |||
const component = renderer.create(<Button disabled />); | |||
const tree = component.toJSON(); | |||
expect(tree).toMatchSnapshot(); | |||
}); | |||
it('renders the children', () => { | |||
const children = <p>children</p>; | |||
const component = renderer.create(<Button>{children}</Button>); | |||
const tree = component.toJSON(); | |||
expect(tree).toMatchSnapshot(); | |||
}); | |||
it('renders the props.text instead of children', () => { | |||
const text = 'foo'; | |||
const children = <p>children</p>; | |||
const component = renderer.create(<Button text={text}>{children}</Button>); | |||
const tree = component.toJSON(); | |||
expect(tree).toMatchSnapshot(); | |||
}); | |||
it('renders class="button--block" if props.block given', () => { | |||
const component = renderer.create(<Button block />); | |||
const tree = component.toJSON(); | |||
expect(tree).toMatchSnapshot(); | |||
}); | |||
it('adds class "button-secondary" if props.secondary given', () => { | |||
const component = renderer.create(<Button secondary />); | |||
const tree = component.toJSON(); | |||
expect(tree).toMatchSnapshot(); | |||
}); | |||
}); |
@ -0,0 +1,18 @@ | |||
import React from 'react'; | |||
import renderer from 'react-test-renderer'; | |||
import { fromJS } from 'immutable'; | |||
import DisplayName from '../display_name'; | |||
describe('<DisplayName />', () => { | |||
it('renders display name + account name', () => { | |||
const account = fromJS({ | |||
username: 'bar', | |||
acct: 'bar@baz', | |||
display_name_html: '<p>Foo</p>', | |||
}); | |||
const component = renderer.create(<DisplayName account={account} />); | |||
const tree = component.toJSON(); | |||
expect(tree).toMatchSnapshot(); | |||
}); | |||
}); |
@ -1,15 +0,0 @@ | |||
import { connect } from 'react-redux'; | |||
import AutosuggestStatus from '../components/autosuggest_status'; | |||
import { makeGetStatus } from '../../../selectors'; | |||
const makeMapStateToProps = () => { | |||
const getStatus = makeGetStatus(); | |||
const mapStateToProps = (state, { id }) => ({ | |||
status: getStatus(state, id), | |||
}); | |||
return mapStateToProps; | |||
}; | |||
export default connect(makeMapStateToProps)(AutosuggestStatus); |
@ -0,0 +1,61 @@ | |||
import emojify from '../emoji'; | |||
describe('emoji', () => { | |||
describe('.emojify', () => { | |||
it('ignores unknown shortcodes', () => { | |||
expect(emojify(':foobarbazfake:')).toEqual(':foobarbazfake:'); | |||
}); | |||
it('ignores shortcodes inside of tags', () => { | |||
expect(emojify('<p data-foo=":smile:"></p>')).toEqual('<p data-foo=":smile:"></p>'); | |||
}); | |||
it('works with unclosed tags', () => { | |||
expect(emojify('hello>')).toEqual('hello>'); | |||
expect(emojify('<hello')).toEqual('<hello'); | |||
}); | |||
it('works with unclosed shortcodes', () => { | |||
expect(emojify('smile:')).toEqual('smile:'); | |||
expect(emojify(':smile')).toEqual(':smile'); | |||
}); | |||
it('does unicode', () => { | |||
expect(emojify('\uD83D\uDC69\u200D\uD83D\uDC69\u200D\uD83D\uDC66\u200D\uD83D\uDC66')).toEqual( | |||
'<img draggable="false" class="emojione" alt="👩👩👦👦" title=":woman-woman-boy-boy:" src="/emoji/1f469-200d-1f469-200d-1f466-200d-1f466.svg" />'); | |||
expect(emojify('👨👩👧👧')).toEqual( | |||
'<img draggable="false" class="emojione" alt="👨👩👧👧" title=":man-woman-girl-girl:" src="/emoji/1f468-200d-1f469-200d-1f467-200d-1f467.svg" />'); | |||
expect(emojify('👩👩👦')).toEqual('<img draggable="false" class="emojione" alt="👩👩👦" title=":woman-woman-boy:" src="/emoji/1f469-200d-1f469-200d-1f466.svg" />'); | |||
expect(emojify('\u2757')).toEqual( | |||
'<img draggable="false" class="emojione" alt="❗" title=":exclamation:" src="/emoji/2757.svg" />'); | |||
}); | |||
it('does multiple unicode', () => { | |||
expect(emojify('\u2757 #\uFE0F\u20E3')).toEqual( | |||
'<img draggable="false" class="emojione" alt="❗" title=":exclamation:" src="/emoji/2757.svg" /> <img draggable="false" class="emojione" alt="#️⃣" title=":hash:" src="/emoji/23-20e3.svg" />'); | |||
expect(emojify('\u2757#\uFE0F\u20E3')).toEqual( | |||
'<img draggable="false" class="emojione" alt="❗" title=":exclamation:" src="/emoji/2757.svg" /><img draggable="false" class="emojione" alt="#️⃣" title=":hash:" src="/emoji/23-20e3.svg" />'); | |||
expect(emojify('\u2757 #\uFE0F\u20E3 \u2757')).toEqual( | |||
'<img draggable="false" class="emojione" alt="❗" title=":exclamation:" src="/emoji/2757.svg" /> <img draggable="false" class="emojione" alt="#️⃣" title=":hash:" src="/emoji/23-20e3.svg" /> <img draggable="false" class="emojione" alt="❗" title=":exclamation:" src="/emoji/2757.svg" />'); | |||
expect(emojify('foo \u2757 #\uFE0F\u20E3 bar')).toEqual( | |||
'foo <img draggable="false" class="emojione" alt="❗" title=":exclamation:" src="/emoji/2757.svg" /> <img draggable="false" class="emojione" alt="#️⃣" title=":hash:" src="/emoji/23-20e3.svg" /> bar'); | |||
}); | |||
it('ignores unicode inside of tags', () => { | |||
expect(emojify('<p data-foo="\uD83D\uDC69\uD83D\uDC69\uD83D\uDC66"></p>')).toEqual('<p data-foo="\uD83D\uDC69\uD83D\uDC69\uD83D\uDC66"></p>'); | |||
}); | |||
it('does multiple emoji properly (issue 5188)', () => { | |||
expect(emojify('👌🌈💕')).toEqual('<img draggable="false" class="emojione" alt="👌" title=":ok_hand:" src="/emoji/1f44c.svg" /><img draggable="false" class="emojione" alt="🌈" title=":rainbow:" src="/emoji/1f308.svg" /><img draggable="false" class="emojione" alt="💕" title=":two_hearts:" src="/emoji/1f495.svg" />'); | |||
expect(emojify('👌 🌈 💕')).toEqual('<img draggable="false" class="emojione" alt="👌" title=":ok_hand:" src="/emoji/1f44c.svg" /> <img draggable="false" class="emojione" alt="🌈" title=":rainbow:" src="/emoji/1f308.svg" /> <img draggable="false" class="emojione" alt="💕" title=":two_hearts:" src="/emoji/1f495.svg" />'); | |||
}); | |||
it('does an emoji that has no shortcode', () => { | |||
expect(emojify('🕉️')).toEqual('<img draggable="false" class="emojione" alt="🕉️" title="" src="/emoji/1f549.svg" />'); | |||
}); | |||
it('does an emoji whose filename is irregular', () => { | |||
expect(emojify('↙️')).toEqual('<img draggable="false" class="emojione" alt="↙️" title=":arrow_lower_left:" src="/emoji/2199.svg" />'); | |||
}); | |||
}); | |||
}); |
@ -0,0 +1,130 @@ | |||
import { pick } from 'lodash'; | |||
import { emojiIndex } from 'emoji-mart'; | |||
import { search } from '../emoji_mart_search_light'; | |||
const trimEmojis = emoji => pick(emoji, ['id', 'unified', 'native', 'custom']); | |||
describe('emoji_index', () => { | |||
it('should give same result for emoji_index_light and emoji-mart', () => { | |||
const expected = [ | |||
{ | |||
id: 'pineapple', | |||
unified: '1f34d', | |||
native: '🍍', | |||
}, | |||
]; | |||
expect(search('pineapple').map(trimEmojis)).toEqual(expected); | |||
expect(emojiIndex.search('pineapple').map(trimEmojis)).toEqual(expected); | |||
}); | |||
it('orders search results correctly', () => { | |||
const expected = [ | |||
{ | |||
id: 'apple', | |||
unified: '1f34e', | |||
native: '🍎', | |||
}, | |||
{ | |||
id: 'pineapple', | |||
unified: '1f34d', | |||
native: '🍍', | |||
}, | |||
{ | |||
id: 'green_apple', | |||
unified: '1f34f', | |||
native: '🍏', | |||
}, | |||
{ | |||
id: 'iphone', | |||
unified: '1f4f1', | |||
native: '📱', | |||
}, | |||
]; | |||
expect(search('apple').map(trimEmojis)).toEqual(expected); | |||
expect(emojiIndex.search('apple').map(trimEmojis)).toEqual(expected); | |||
}); | |||
it('handles custom emoji', () => { | |||
const custom = [ | |||
{ | |||
id: 'mastodon', | |||
name: 'mastodon', | |||
short_names: ['mastodon'], | |||
text: '', | |||
emoticons: [], | |||
keywords: ['mastodon'], | |||
imageUrl: 'http://example.com', | |||
custom: true, | |||
}, | |||
]; | |||
search('', { custom }); | |||
emojiIndex.search('', { custom }); | |||
const expected = [ | |||
{ | |||
id: 'mastodon', | |||
custom: true, | |||
}, | |||
]; | |||
expect(search('masto').map(trimEmojis)).toEqual(expected); | |||
expect(emojiIndex.search('masto').map(trimEmojis)).toEqual(expected); | |||
}); | |||
it('should filter only emojis we care about, exclude pineapple', () => { | |||
const emojisToShowFilter = unified => unified !== '1F34D'; | |||
expect(search('apple', { emojisToShowFilter }).map((obj) => obj.id)) | |||
.not.toContain('pineapple'); | |||
expect(emojiIndex.search('apple', { emojisToShowFilter }).map((obj) => obj.id)) | |||
.not.toContain('pineapple'); | |||
}); | |||
it('can include/exclude categories', () => { | |||
expect(search('flag', { include: ['people'] })).toEqual([]); | |||
expect(emojiIndex.search('flag', { include: ['people'] })).toEqual([]); | |||
}); | |||
it('does an emoji whose unified name is irregular', () => { | |||
const expected = [ | |||
{ | |||
'id': 'water_polo', | |||
'unified': '1f93d', | |||
'native': '🤽', | |||
}, | |||
{ | |||
'id': 'man-playing-water-polo', | |||
'unified': '1f93d-200d-2642-fe0f', | |||
'native': '🤽♂️', | |||
}, | |||
{ | |||
'id': 'woman-playing-water-polo', | |||
'unified': '1f93d-200d-2640-fe0f', | |||
'native': '🤽♀️', | |||
}, | |||
]; | |||
expect(search('polo').map(trimEmojis)).toEqual(expected); | |||
expect(emojiIndex.search('polo').map(trimEmojis)).toEqual(expected); | |||
}); | |||
it('can search for thinking_face', () => { | |||
const expected = [ | |||
{ | |||
id: 'thinking_face', | |||
unified: '1f914', | |||
native: '🤔', | |||
}, | |||
]; | |||
expect(search('thinking_fac').map(trimEmojis)).toEqual(expected); | |||
expect(emojiIndex.search('thinking_fac').map(trimEmojis)).toEqual(expected); | |||
}); | |||
it('can search for woman-facepalming', () => { | |||
const expected = [ | |||
{ | |||
id: 'woman-facepalming', | |||
unified: '1f926-200d-2640-fe0f', | |||
native: '🤦♀️', | |||
}, | |||
]; | |||
expect(search('woman-facep').map(trimEmojis)).toEqual(expected); | |||
expect(emojiIndex.search('woman-facep').map(trimEmojis)).toEqual(expected); | |||
}); | |||
}); |
@ -0,0 +1,34 @@ | |||
// Like react-motion's Motion, but checks to see if the user prefers | |||
// reduced motion and uses a cross-fade in those cases. | |||
import Motion from 'react-motion/lib/Motion'; | |||
import { connect } from 'react-redux'; | |||
const stylesToKeep = ['opacity', 'backgroundOpacity']; | |||
const extractValue = (value) => { | |||
// This is either an object with a "val" property or it's a number | |||
return (typeof value === 'object' && value && 'val' in value) ? value.val : value; | |||
}; | |||
const mapStateToProps = (state, ownProps) => { | |||
const reduceMotion = state.getIn(['meta', 'reduce_motion']); | |||
if (reduceMotion) { | |||
const { style, defaultStyle } = ownProps; | |||
Object.keys(style).forEach(key => { | |||
if (stylesToKeep.includes(key)) { | |||
return; | |||
} | |||
// If it's setting an x or height or scale or some other value, we need | |||
// to preserve the end-state value without actually animating it | |||
style[key] = defaultStyle[key] = extractValue(style[key]); | |||
}); | |||
return { style, defaultStyle }; | |||
} | |||
return {}; | |||
}; | |||
export default connect(mapStateToProps)(Motion); |
@ -0,0 +1,5 @@ | |||
import { configure } from 'enzyme'; | |||
import Adapter from 'enzyme-adapter-react-16'; | |||
const adapter = new Adapter(); | |||
configure({ adapter }); |
@ -1,6 +1,8 @@ | |||
import { start } from 'rails-ujs'; | |||
import 'font-awesome/css/font-awesome.css'; | |||
// import common styling | |||
require('../styles/common.scss'); | |||
require.context('../images/', true); | |||
start(); |
@ -0,0 +1,17 @@ | |||
module.exports = { | |||
projects: [ | |||
'<rootDir>/app/javascript/mastodon', | |||
], | |||
testPathIgnorePatterns: [ | |||
'<rootDir>/node_modules/', | |||
'<rootDir>/vendor/', | |||
'<rootDir>/config/', | |||
'<rootDir>/log/', | |||
'<rootDir>/public/', | |||
'<rootDir>/tmp/', | |||
], | |||
setupFiles: [ | |||
'raf/polyfill', | |||
], | |||
setupTestFrameworkScriptFile: '<rootDir>/app/javascript/mastodon/test_setup.js', | |||
}; |
@ -1,3 +0,0 @@ | |||
env: | |||
mocha: true |
@ -1,44 +0,0 @@ | |||
import React from 'react'; | |||
import Avatar from '../../../app/javascript/mastodon/components/avatar'; | |||
import { expect } from 'chai'; | |||
import { render } from 'enzyme'; | |||
import { fromJS } from 'immutable'; | |||
describe('<Avatar />', () => { | |||
const account = fromJS({ | |||
username: 'alice', | |||
acct: 'alice', | |||
display_name: 'Alice', | |||
avatar: '/animated/alice.gif', | |||
avatar_static: '/static/alice.jpg', | |||
}); | |||
const size = 100; | |||
const animated = render(<Avatar account={account} animate size={size} />); | |||
const still = render(<Avatar account={account} size={size} />); | |||
// Autoplay | |||
xit('renders a div element with the given src as background', () => { | |||
expect(animated.find('div')).to.have.style('background-image', `url(${account.get('avatar')})`); | |||
}); | |||
xit('renders a div element of the given size', () => { | |||
['width', 'height'].map((attr) => { | |||
expect(animated.find('div')).to.have.style(attr, `${size}px`); | |||
}); | |||
}); | |||
// Still | |||
xit('renders a div element with the given static src as background if not autoplay', () => { | |||
expect(still.find('div')).to.have.style('background-image', `url(${account.get('avatar_static')})`); | |||
}); | |||
xit('renders a div element of the given size if not autoplay', () => { | |||
['width', 'height'].map((attr) => { | |||
expect(still.find('div')).to.have.style(attr, `${size}px`); | |||
}); | |||
}); | |||
// TODO add autoplay test if possible | |||
}); |
@ -1,36 +0,0 @@ | |||
import React from 'react'; | |||
import AvatarOverlay from '../../../app/javascript/mastodon/components/avatar_overlay'; | |||
import { expect } from 'chai'; | |||
import { render } from 'enzyme'; | |||
import { fromJS } from 'immutable'; | |||
describe('<Avatar />', () => { | |||
const account = fromJS({ | |||
username: 'alice', | |||
acct: 'alice', | |||
display_name: 'Alice', | |||
avatar: '/animated/alice.gif', | |||
avatar_static: '/static/alice.jpg', | |||
}); | |||
const friend = fromJS({ | |||
username: 'eve', | |||
acct: 'eve@blackhat.lair', | |||
display_name: 'Evelyn', | |||
avatar: '/animated/eve.gif', | |||
avatar_static: '/static/eve.jpg', | |||
}); | |||
const overlay = render(<AvatarOverlay account={account} friend={friend} />); | |||
xit('renders account static src as base of overlay avatar', () => { | |||
expect(overlay.find('.account__avatar-overlay-base')) | |||
.to.have.style('background-image', `url(${account.get('avatar_static')})`); | |||
}); | |||
xit('renders friend static src as overlay of overlay avatar', () => { | |||
expect(overlay.find('.account__avatar-overlay-overlay')) | |||
.to.have.style('background-image', `url(${friend.get('avatar_static')})`); | |||
}); | |||
}); |
@ -1,72 +0,0 @@ | |||
import React from 'react'; | |||
import Button from '../../../app/javascript/mastodon/components/button'; | |||
import { expect } from 'chai'; | |||
import { shallow } from 'enzyme'; | |||
import sinon from 'sinon'; | |||
describe('<Button />', () => { | |||
xit('renders a button element', () => { | |||
const wrapper = shallow(<Button />); | |||
expect(wrapper).to.match('button'); | |||
}); | |||
xit('renders the given text', () => { | |||
const text = 'foo'; | |||
const wrapper = shallow(<Button text={text} />); | |||
expect(wrapper.find('button')).to.have.text(text); | |||
}); | |||
it('handles click events using the given handler', () => { | |||
const handler = sinon.spy(); | |||
const wrapper = shallow(<Button onClick={handler} />); | |||
wrapper.find('button').simulate('click'); | |||
expect(handler.calledOnce).to.equal(true); | |||
}); | |||
it('does not handle click events if props.disabled given', () => { | |||
const handler = sinon.spy(); | |||
const wrapper = shallow(<Button onClick={handler} disabled />); | |||
wrapper.find('button').simulate('click'); | |||
expect(handler.called).to.equal(false); | |||
}); | |||
xit('renders a disabled attribute if props.disabled given', () => { | |||
const wrapper = shallow(<Button disabled />); | |||
expect(wrapper.find('button')).to.be.disabled(); | |||
}); | |||
xit('renders the children', () => { | |||
const children = <p>children</p>; | |||
const wrapper = shallow(<Button>{children}</Button>); | |||
expect(wrapper.find('button')).to.contain(children); | |||
}); | |||
xit('renders the props.text instead of children', () => { | |||
const text = 'foo'; | |||
const children = <p>children</p>; | |||
const wrapper = shallow(<Button text={text}>{children}</Button>); | |||
expect(wrapper.find('button')).to.have.text(text); | |||
expect(wrapper.find('button')).to.not.contain(children); | |||
}); | |||
xit('renders style="display: block; width: 100%;" if props.block given', () => { | |||
const wrapper = shallow(<Button block />); | |||
expect(wrapper.find('button')).to.have.className('button--block'); | |||
}); | |||
xit('renders style="display: inline-block; width: auto;" by default', () => { | |||
const wrapper = shallow(<Button />); | |||
expect(wrapper.find('button')).to.not.have.className('button--block'); | |||
}); | |||
xit('adds class "button-secondary" if props.secondary given', () => { | |||
const wrapper = shallow(<Button secondary />); | |||
expect(wrapper.find('button')).to.have.className('button-secondary'); | |||
}); | |||
xit('does not add class "button-secondary" by default', () => { | |||
const wrapper = shallow(<Button />); | |||
expect(wrapper.find('button')).to.not.have.className('button-secondary'); | |||
}); | |||
}); |
@ -1,18 +0,0 @@ | |||
import React from 'react'; | |||
import DisplayName from '../../../app/javascript/mastodon/components/display_name'; | |||
import { expect } from 'chai'; | |||
import { render } from 'enzyme'; | |||
import { fromJS } from 'immutable'; | |||
describe('<DisplayName />', () => { | |||
xit('renders display name + account name', () => { | |||
const account = fromJS({ | |||
username: 'bar', | |||
acct: 'bar@baz', | |||
display_name_html: '<p>Foo</p>', | |||
}); | |||
const wrapper = render(<DisplayName account={account} />); | |||
expect(wrapper).to.have.text('Foo @bar@baz'); | |||
}); | |||
}); |
@ -1,111 +0,0 @@ | |||
import { expect } from 'chai'; | |||
import { search } from '../../../app/javascript/mastodon/features/emoji/emoji_mart_search_light'; | |||
import { emojiIndex } from 'emoji-mart'; | |||
import { pick } from 'lodash'; | |||
const trimEmojis = emoji => pick(emoji, ['id', 'unified', 'native', 'custom']); | |||
// hack to fix https://github.com/chaijs/type-detect/issues/98 | |||
// see: https://github.com/chaijs/type-detect/issues/98#issuecomment-325010785 | |||
import jsdom from 'jsdom'; | |||
global.window = new jsdom.JSDOM().window; | |||
global.document = window.document; | |||
global.HTMLElement = window.HTMLElement; | |||
describe('emoji_index', () => { | |||
it('should give same result for emoji_index_light and emoji-mart', () => { | |||
let expected = [{ | |||
id: 'pineapple', | |||
unified: '1f34d', | |||
native: '🍍', | |||
}]; | |||
expect(search('pineapple').map(trimEmojis)).to.deep.equal(expected); | |||
expect(emojiIndex.search('pineapple').map(trimEmojis)).to.deep.equal(expected); | |||
}); | |||
it('orders search results correctly', () => { | |||
let expected = [{ | |||
id: 'apple', | |||
unified: '1f34e', | |||
native: '🍎', | |||
}, { | |||
id: 'pineapple', | |||
unified: '1f34d', | |||
native: '🍍', | |||
}, { | |||
id: 'green_apple', | |||
unified: '1f34f', | |||
native: '🍏', | |||
}, { | |||
id: 'iphone', | |||
unified: '1f4f1', | |||
native: '📱', | |||
}]; | |||
expect(search('apple').map(trimEmojis)).to.deep.equal(expected); | |||
expect(emojiIndex.search('apple').map(trimEmojis)).to.deep.equal(expected); | |||
}); | |||
it('handles custom emoji', () => { | |||
let custom = [{ | |||
id: 'mastodon', | |||
name: 'mastodon', | |||
short_names: ['mastodon'], | |||
text: '', | |||
emoticons: [], | |||
keywords: ['mastodon'], | |||
imageUrl: 'http://example.com', | |||
custom: true, | |||
}]; | |||
search('', { custom }); | |||
emojiIndex.search('', { custom }); | |||
let expected = [ { id: 'mastodon', custom: true } ]; | |||
expect(search('masto').map(trimEmojis)).to.deep.equal(expected); | |||
expect(emojiIndex.search('masto').map(trimEmojis)).to.deep.equal(expected); | |||
}); | |||
it('should filter only emojis we care about, exclude pineapple', () => { | |||
let emojisToShowFilter = (unified) => unified !== '1F34D'; | |||
expect(search('apple', { emojisToShowFilter }).map((obj) => obj.id)) | |||
.not.to.contain('pineapple'); | |||
expect(emojiIndex.search('apple', { emojisToShowFilter }).map((obj) => obj.id)) | |||
.not.to.contain('pineapple'); | |||
}); | |||
it('can include/exclude categories', () => { | |||
expect(search('flag', { include: ['people'] })) | |||
.to.deep.equal([]); | |||
expect(emojiIndex.search('flag', { include: ['people'] })) | |||
.to.deep.equal([]); | |||
}); | |||
it('does an emoji whose unified name is irregular', () => { | |||
let expected = [{ | |||
'id': 'water_polo', | |||
'unified': '1f93d', | |||
'native': '🤽', | |||
}, { | |||
'id': 'man-playing-water-polo', | |||
'unified': '1f93d-200d-2642-fe0f', | |||
'native': '🤽♂️', | |||
}, { | |||
'id': 'woman-playing-water-polo', | |||
'unified': '1f93d-200d-2640-fe0f', | |||
'native': '🤽♀️', | |||
}]; | |||
expect(search('polo').map(trimEmojis)).to.deep.equal(expected); | |||
expect(emojiIndex.search('polo').map(trimEmojis)).to.deep.equal(expected); | |||
}); | |||
it('can search for thinking_face', () => { | |||
let expected = [ { id: 'thinking_face', unified: '1f914', native: '🤔' } ]; | |||
expect(search('thinking_fac').map(trimEmojis)).to.deep.equal(expected); | |||
expect(emojiIndex.search('thinking_fac').map(trimEmojis)).to.deep.equal(expected); | |||
}); | |||
it('can search for woman-facepalming', () => { | |||
let expected = [ { id: 'woman-facepalming', unified: '1f926-200d-2640-fe0f', native: '🤦♀️' } ]; | |||
expect(search('woman-facep').map(trimEmojis)).to.deep.equal(expected); | |||
expect(emojiIndex.search('woman-facep').map(trimEmojis)).deep.equal(expected); | |||
}); | |||
}); |
@ -1,61 +0,0 @@ | |||
import { expect } from 'chai'; | |||
import emojify from '../../../app/javascript/mastodon/features/emoji/emoji'; | |||
describe('emojify', () => { | |||
it('ignores unknown shortcodes', () => { | |||
expect(emojify(':foobarbazfake:')).to.equal(':foobarbazfake:'); | |||
}); | |||
it('ignores shortcodes inside of tags', () => { | |||
expect(emojify('<p data-foo=":smile:"></p>')).to.equal('<p data-foo=":smile:"></p>'); | |||
}); | |||
it('works with unclosed tags', () => { | |||
expect(emojify('hello>')).to.equal('hello>'); | |||
expect(emojify('<hello')).to.equal('<hello'); | |||
}); | |||
it('works with unclosed shortcodes', () => { | |||
expect(emojify('smile:')).to.equal('smile:'); | |||
expect(emojify(':smile')).to.equal(':smile'); | |||
}); | |||
it('does unicode', () => { | |||
expect(emojify('\uD83D\uDC69\u200D\uD83D\uDC69\u200D\uD83D\uDC66\u200D\uD83D\uDC66')).to.equal( | |||
'<img draggable="false" class="emojione" alt="👩👩👦👦" title=":woman-woman-boy-boy:" src="/emoji/1f469-200d-1f469-200d-1f466-200d-1f466.svg" />'); | |||
expect(emojify('👨👩👧👧')).to.equal( | |||
'<img draggable="false" class="emojione" alt="👨👩👧👧" title=":man-woman-girl-girl:" src="/emoji/1f468-200d-1f469-200d-1f467-200d-1f467.svg" />'); | |||
expect(emojify('👩👩👦')).to.equal('<img draggable="false" class="emojione" alt="👩👩👦" title=":woman-woman-boy:" src="/emoji/1f469-200d-1f469-200d-1f466.svg" />'); | |||
expect(emojify('\u2757')).to.equal( | |||
'<img draggable="false" class="emojione" alt="❗" title=":exclamation:" src="/emoji/2757.svg" />'); | |||
}); | |||
it('does multiple unicode', () => { | |||
expect(emojify('\u2757 #\uFE0F\u20E3')).to.equal( | |||
'<img draggable="false" class="emojione" alt="❗" title=":exclamation:" src="/emoji/2757.svg" /> <img draggable="false" class="emojione" alt="#️⃣" title=":hash:" src="/emoji/23-20e3.svg" />'); | |||
expect(emojify('\u2757#\uFE0F\u20E3')).to.equal( | |||
'<img draggable="false" class="emojione" alt="❗" title=":exclamation:" src="/emoji/2757.svg" /><img draggable="false" class="emojione" alt="#️⃣" title=":hash:" src="/emoji/23-20e3.svg" />'); | |||
expect(emojify('\u2757 #\uFE0F\u20E3 \u2757')).to.equal( | |||
'<img draggable="false" class="emojione" alt="❗" title=":exclamation:" src="/emoji/2757.svg" /> <img draggable="false" class="emojione" alt="#️⃣" title=":hash:" src="/emoji/23-20e3.svg" /> <img draggable="false" class="emojione" alt="❗" title=":exclamation:" src="/emoji/2757.svg" />'); | |||
expect(emojify('foo \u2757 #\uFE0F\u20E3 bar')).to.equal( | |||
'foo <img draggable="false" class="emojione" alt="❗" title=":exclamation:" src="/emoji/2757.svg" /> <img draggable="false" class="emojione" alt="#️⃣" title=":hash:" src="/emoji/23-20e3.svg" /> bar'); | |||
}); | |||
it('ignores unicode inside of tags', () => { | |||
expect(emojify('<p data-foo="\uD83D\uDC69\uD83D\uDC69\uD83D\uDC66"></p>')).to.equal('<p data-foo="\uD83D\uDC69\uD83D\uDC69\uD83D\uDC66"></p>'); | |||
}); | |||
it('does multiple emoji properly (issue 5188)', () => { | |||
expect(emojify('👌🌈💕')).to.equal('<img draggable="false" class="emojione" alt="👌" title=":ok_hand:" src="/emoji/1f44c.svg" /><img draggable="false" class="emojione" alt="🌈" title=":rainbow:" src="/emoji/1f308.svg" /><img draggable="false" class="emojione" alt="💕" title=":two_hearts:" src="/emoji/1f495.svg" />'); | |||
expect(emojify('👌 🌈 💕')).to.equal('<img draggable="false" class="emojione" alt="👌" title=":ok_hand:" src="/emoji/1f44c.svg" /> <img draggable="false" class="emojione" alt="🌈" title=":rainbow:" src="/emoji/1f308.svg" /> <img draggable="false" class="emojione" alt="💕" title=":two_hearts:" src="/emoji/1f495.svg" />'); | |||
}); | |||
it('does an emoji that has no shortcode', () => { | |||
expect(emojify('🕉️')).to.equal('<img draggable="false" class="emojione" alt="🕉️" title="" src="/emoji/1f549.svg" />'); | |||
}); | |||
it('does an emoji whose filename is irregular', () => { | |||
expect(emojify('↙️')).to.equal('<img draggable="false" class="emojione" alt="↙️" title=":arrow_lower_left:" src="/emoji/2199.svg" />'); | |||
}); | |||
}); |
@ -1,15 +0,0 @@ | |||
import { JSDOM } from 'jsdom'; | |||
import Enzyme from 'enzyme'; | |||
import Adapter from 'enzyme-adapter-react-16'; | |||
Enzyme.configure({ adapter: new Adapter() }); | |||
const { window } = new JSDOM('', { | |||
userAgent: 'node.js', | |||
}); | |||
Object.keys(window).forEach(property => { | |||
if (typeof global[property] === 'undefined') { | |||
global[property] = window[property]; | |||
} | |||
}); |