Convert old tests to use "react-testing-library"
This commit is contained in:
parent
9a099b3fa7
commit
ed47cf5f09
71 changed files with 411 additions and 1515 deletions
18
.eslintrc.js
18
.eslintrc.js
|
@ -217,15 +217,15 @@ module.exports = {
|
||||||
'import/newline-after-import': 'error',
|
'import/newline-after-import': 'error',
|
||||||
'import/no-extraneous-dependencies': [
|
'import/no-extraneous-dependencies': [
|
||||||
'error',
|
'error',
|
||||||
{
|
// {
|
||||||
devDependencies: [
|
// devDependencies: [
|
||||||
'webpack/**',
|
// 'webpack/**',
|
||||||
'app/soapbox/test_setup.js',
|
// 'app/soapbox/test_setup.js',
|
||||||
'app/soapbox/test_helpers.js',
|
// 'app/soapbox/test_helpers.js',
|
||||||
'app/**/__tests__/**',
|
// 'app/**/__tests__/**',
|
||||||
'app/**/__mocks__/**',
|
// 'app/**/__mocks__/**',
|
||||||
],
|
// ],
|
||||||
},
|
// },
|
||||||
],
|
],
|
||||||
'import/no-unresolved': 'error',
|
'import/no-unresolved': 'error',
|
||||||
'import/no-webpack-loader-syntax': 'error',
|
'import/no-webpack-loader-syntax': 'error',
|
||||||
|
|
|
@ -2,7 +2,7 @@ import MockAdapter from 'axios-mock-adapter';
|
||||||
import { Map as ImmutableMap } from 'immutable';
|
import { Map as ImmutableMap } from 'immutable';
|
||||||
|
|
||||||
import { staticClient } from 'soapbox/api';
|
import { staticClient } from 'soapbox/api';
|
||||||
import { mockStore } from 'soapbox/test_helpers';
|
import { mockStore } from 'soapbox/jest/test-helpers';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
FETCH_ABOUT_PAGE_REQUEST,
|
FETCH_ABOUT_PAGE_REQUEST,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
|
import { mockStore } from 'soapbox/jest/test-helpers';
|
||||||
import { InstanceRecord } from 'soapbox/normalizers';
|
import { InstanceRecord } from 'soapbox/normalizers';
|
||||||
import rootReducer from 'soapbox/reducers';
|
import rootReducer from 'soapbox/reducers';
|
||||||
import { mockStore } from 'soapbox/test_helpers';
|
|
||||||
|
|
||||||
import { uploadCompose } from '../compose';
|
import { uploadCompose } from '../compose';
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { Map as ImmutableMap } from 'immutable';
|
import { Map as ImmutableMap } from 'immutable';
|
||||||
|
|
||||||
import { __stub } from 'soapbox/api';
|
import { __stub } from 'soapbox/api';
|
||||||
import { mockStore } from 'soapbox/test_helpers';
|
import { mockStore } from 'soapbox/jest/test-helpers';
|
||||||
|
|
||||||
import { VERIFY_CREDENTIALS_REQUEST } from '../auth';
|
import { VERIFY_CREDENTIALS_REQUEST } from '../auth';
|
||||||
import { ACCOUNTS_IMPORT } from '../importer';
|
import { ACCOUNTS_IMPORT } from '../importer';
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { STATUSES_IMPORT } from 'soapbox/actions/importer';
|
import { STATUSES_IMPORT } from 'soapbox/actions/importer';
|
||||||
import { __stub } from 'soapbox/api';
|
import { __stub } from 'soapbox/api';
|
||||||
import { mockStore, rootState } from 'soapbox/test_helpers';
|
import { mockStore, rootState } from 'soapbox/jest/test-helpers';
|
||||||
|
|
||||||
import { fetchContext } from '../statuses';
|
import { fetchContext } from '../statuses';
|
||||||
|
|
||||||
|
|
|
@ -1,27 +0,0 @@
|
||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
||||||
|
|
||||||
exports[`<AutosuggestEmoji /> renders emoji with custom url 1`] = `
|
|
||||||
<div
|
|
||||||
className="autosuggest-emoji"
|
|
||||||
>
|
|
||||||
<img
|
|
||||||
alt="foobar"
|
|
||||||
className="emojione"
|
|
||||||
src="http://example.com/emoji.png"
|
|
||||||
/>
|
|
||||||
:foobar:
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`<AutosuggestEmoji /> renders native emoji 1`] = `
|
|
||||||
<div
|
|
||||||
className="autosuggest-emoji"
|
|
||||||
>
|
|
||||||
<img
|
|
||||||
alt="💙"
|
|
||||||
className="emojione"
|
|
||||||
src="/packs/emoji/1f499.svg"
|
|
||||||
/>
|
|
||||||
:foobar:
|
|
||||||
</div>
|
|
||||||
`;
|
|
|
@ -1,37 +0,0 @@
|
||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
||||||
|
|
||||||
exports[`<Avatar /> Autoplay renders an animated avatar 1`] = `
|
|
||||||
<div
|
|
||||||
className="rounded-full still-image"
|
|
||||||
style={
|
|
||||||
Object {
|
|
||||||
"height": "100px",
|
|
||||||
"width": "100px",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<img
|
|
||||||
alt=""
|
|
||||||
onLoad={[Function]}
|
|
||||||
src="/animated/alice.gif"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`<Avatar /> Still renders a still avatar 1`] = `
|
|
||||||
<div
|
|
||||||
className="rounded-full still-image"
|
|
||||||
style={
|
|
||||||
Object {
|
|
||||||
"height": "100px",
|
|
||||||
"width": "100px",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<img
|
|
||||||
alt=""
|
|
||||||
onLoad={[Function]}
|
|
||||||
src="/animated/alice.gif"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
`;
|
|
|
@ -1,28 +0,0 @@
|
||||||
// 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 still-image"
|
|
||||||
style={Object {}}
|
|
||||||
>
|
|
||||||
<img
|
|
||||||
alt=""
|
|
||||||
onLoad={[Function]}
|
|
||||||
src="/animated/alice.gif"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className="account__avatar-overlay-overlay still-image"
|
|
||||||
style={Object {}}
|
|
||||||
>
|
|
||||||
<img
|
|
||||||
alt=""
|
|
||||||
onLoad={[Function]}
|
|
||||||
src="/animated/eve.gif"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
`;
|
|
|
@ -1,9 +0,0 @@
|
||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
||||||
|
|
||||||
exports[`<Badge /> renders correctly 1`] = `
|
|
||||||
<span
|
|
||||||
className="badge badge--patron"
|
|
||||||
>
|
|
||||||
Patron
|
|
||||||
</span>
|
|
||||||
`;
|
|
|
@ -1,16 +0,0 @@
|
||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
||||||
|
|
||||||
exports[`<ColumnBackButton /> renders correctly 1`] = `
|
|
||||||
<button
|
|
||||||
className="column-back-button"
|
|
||||||
onClick={[Function]}
|
|
||||||
onKeyUp={[Function]}
|
|
||||||
>
|
|
||||||
<i
|
|
||||||
alt="chevron-left"
|
|
||||||
className="fa fa-chevron-left column-back-button__icon fa-fw"
|
|
||||||
role="img"
|
|
||||||
/>
|
|
||||||
Back
|
|
||||||
</button>
|
|
||||||
`;
|
|
|
@ -1,35 +0,0 @@
|
||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
||||||
|
|
||||||
exports[`<DisplayName /> renders display name + account name 1`] = `
|
|
||||||
<span
|
|
||||||
className="display-name"
|
|
||||||
>
|
|
||||||
<span
|
|
||||||
className="hover-ref-wrapper"
|
|
||||||
onClick={[Function]}
|
|
||||||
onMouseEnter={[Function]}
|
|
||||||
onMouseLeave={[Function]}
|
|
||||||
>
|
|
||||||
<span
|
|
||||||
className="display-name__name"
|
|
||||||
>
|
|
||||||
<bdi>
|
|
||||||
<strong
|
|
||||||
className="display-name__html"
|
|
||||||
dangerouslySetInnerHTML={
|
|
||||||
Object {
|
|
||||||
"__html": "bar",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</bdi>
|
|
||||||
</span>
|
|
||||||
</span>
|
|
||||||
<span
|
|
||||||
className="display-name__account"
|
|
||||||
>
|
|
||||||
@
|
|
||||||
bar@baz
|
|
||||||
</span>
|
|
||||||
</span>
|
|
||||||
`;
|
|
|
@ -1,86 +0,0 @@
|
||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
||||||
|
|
||||||
exports[`<EmojiSelector /> renders correctly 1`] = `
|
|
||||||
<div
|
|
||||||
onBlur={[Function]}
|
|
||||||
onFocus={[Function]}
|
|
||||||
tabIndex="-1"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className="flex space-x-2 bg-white dark:bg-slate-900 p-3 rounded-full shadow-md z-[999] w-max"
|
|
||||||
>
|
|
||||||
<button
|
|
||||||
className=""
|
|
||||||
onClick={[Function]}
|
|
||||||
tabIndex={-1}
|
|
||||||
>
|
|
||||||
<img
|
|
||||||
alt="👍"
|
|
||||||
className="w-8 h-8 duration-100 hover:scale-125"
|
|
||||||
draggable="false"
|
|
||||||
src="/packs/emoji/1f44d.svg"
|
|
||||||
/>
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
className=""
|
|
||||||
onClick={[Function]}
|
|
||||||
tabIndex={-1}
|
|
||||||
>
|
|
||||||
<img
|
|
||||||
alt="❤"
|
|
||||||
className="w-8 h-8 duration-100 hover:scale-125"
|
|
||||||
draggable="false"
|
|
||||||
src="/packs/emoji/2764.svg"
|
|
||||||
/>
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
className=""
|
|
||||||
onClick={[Function]}
|
|
||||||
tabIndex={-1}
|
|
||||||
>
|
|
||||||
<img
|
|
||||||
alt="😆"
|
|
||||||
className="w-8 h-8 duration-100 hover:scale-125"
|
|
||||||
draggable="false"
|
|
||||||
src="/packs/emoji/1f606.svg"
|
|
||||||
/>
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
className=""
|
|
||||||
onClick={[Function]}
|
|
||||||
tabIndex={-1}
|
|
||||||
>
|
|
||||||
<img
|
|
||||||
alt="😮"
|
|
||||||
className="w-8 h-8 duration-100 hover:scale-125"
|
|
||||||
draggable="false"
|
|
||||||
src="/packs/emoji/1f62e.svg"
|
|
||||||
/>
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
className=""
|
|
||||||
onClick={[Function]}
|
|
||||||
tabIndex={-1}
|
|
||||||
>
|
|
||||||
<img
|
|
||||||
alt="😢"
|
|
||||||
className="w-8 h-8 duration-100 hover:scale-125"
|
|
||||||
draggable="false"
|
|
||||||
src="/packs/emoji/1f622.svg"
|
|
||||||
/>
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
className=""
|
|
||||||
onClick={[Function]}
|
|
||||||
tabIndex={-1}
|
|
||||||
>
|
|
||||||
<img
|
|
||||||
alt="😩"
|
|
||||||
className="w-8 h-8 duration-100 hover:scale-125"
|
|
||||||
draggable="false"
|
|
||||||
src="/packs/emoji/1f629.svg"
|
|
||||||
/>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
`;
|
|
|
@ -1,80 +0,0 @@
|
||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
||||||
|
|
||||||
exports[`<TimelineQueueButtonHeader /> renders correctly 1`] = `
|
|
||||||
<div
|
|
||||||
className="left-1/2 -translate-x-1/2 fixed top-20 z-50 hidden"
|
|
||||||
>
|
|
||||||
<a
|
|
||||||
className="flex items-center bg-primary-600 hover:bg-primary-700 hover:scale-105 active:scale-100 transition-transform text-white rounded-full px-4 py-2 space-x-1.5 cursor-pointer"
|
|
||||||
onClick={[Function]}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className="svg-icon"
|
|
||||||
>
|
|
||||||
<svg
|
|
||||||
id={
|
|
||||||
Object {
|
|
||||||
"process": [Function],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`<TimelineQueueButtonHeader /> renders correctly 2`] = `
|
|
||||||
<div
|
|
||||||
className="left-1/2 -translate-x-1/2 fixed top-20 z-50 hidden"
|
|
||||||
>
|
|
||||||
<a
|
|
||||||
className="flex items-center bg-primary-600 hover:bg-primary-700 hover:scale-105 active:scale-100 transition-transform text-white rounded-full px-4 py-2 space-x-1.5 cursor-pointer"
|
|
||||||
onClick={[Function]}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className="svg-icon"
|
|
||||||
>
|
|
||||||
<svg
|
|
||||||
id={
|
|
||||||
Object {
|
|
||||||
"process": [Function],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<p
|
|
||||||
className="text-sm text-inherit font-normal tracking-normal font-sans"
|
|
||||||
>
|
|
||||||
Click to see 1 new post
|
|
||||||
</p>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`<TimelineQueueButtonHeader /> renders correctly 3`] = `
|
|
||||||
<div
|
|
||||||
className="left-1/2 -translate-x-1/2 fixed top-20 z-50 hidden"
|
|
||||||
>
|
|
||||||
<a
|
|
||||||
className="flex items-center bg-primary-600 hover:bg-primary-700 hover:scale-105 active:scale-100 transition-transform text-white rounded-full px-4 py-2 space-x-1.5 cursor-pointer"
|
|
||||||
onClick={[Function]}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className="svg-icon"
|
|
||||||
>
|
|
||||||
<svg
|
|
||||||
id={
|
|
||||||
Object {
|
|
||||||
"process": [Function],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<p
|
|
||||||
className="text-sm text-inherit font-normal tracking-normal font-sans"
|
|
||||||
>
|
|
||||||
Click to see 9999999 new posts
|
|
||||||
</p>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
`;
|
|
|
@ -1,6 +1,6 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import renderer from 'react-test-renderer';
|
|
||||||
|
|
||||||
|
import { render, screen } from '../../jest/test-helpers';
|
||||||
import AutosuggestEmoji from '../autosuggest_emoji';
|
import AutosuggestEmoji from '../autosuggest_emoji';
|
||||||
|
|
||||||
describe('<AutosuggestEmoji />', () => {
|
describe('<AutosuggestEmoji />', () => {
|
||||||
|
@ -9,10 +9,11 @@ describe('<AutosuggestEmoji />', () => {
|
||||||
native: '💙',
|
native: '💙',
|
||||||
colons: ':foobar:',
|
colons: ':foobar:',
|
||||||
};
|
};
|
||||||
const component = renderer.create(<AutosuggestEmoji emoji={emoji} />);
|
|
||||||
const tree = component.toJSON();
|
|
||||||
|
|
||||||
expect(tree).toMatchSnapshot();
|
render(<AutosuggestEmoji emoji={emoji} />);
|
||||||
|
|
||||||
|
expect(screen.getByTestId('emoji')).toHaveTextContent('foobar');
|
||||||
|
expect(screen.getByRole('img').getAttribute('src')).not.toBe('http://example.com/emoji.png');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders emoji with custom url', () => {
|
it('renders emoji with custom url', () => {
|
||||||
|
@ -22,9 +23,10 @@ describe('<AutosuggestEmoji />', () => {
|
||||||
native: 'foobar',
|
native: 'foobar',
|
||||||
colons: ':foobar:',
|
colons: ':foobar:',
|
||||||
};
|
};
|
||||||
const component = renderer.create(<AutosuggestEmoji emoji={emoji} />);
|
|
||||||
const tree = component.toJSON();
|
|
||||||
|
|
||||||
expect(tree).toMatchSnapshot();
|
render(<AutosuggestEmoji emoji={emoji} />);
|
||||||
|
|
||||||
|
expect(screen.getByTestId('emoji')).toHaveTextContent('foobar');
|
||||||
|
expect(screen.getByRole('img').getAttribute('src')).toBe('http://example.com/emoji.png');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,38 +0,0 @@
|
||||||
import { fromJS } from 'immutable';
|
|
||||||
import React from 'react';
|
|
||||||
|
|
||||||
import { createComponent } from 'soapbox/test_helpers';
|
|
||||||
|
|
||||||
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 an animated avatar', () => {
|
|
||||||
const component = createComponent(<Avatar account={account} animate size={size} />);
|
|
||||||
const tree = component.toJSON();
|
|
||||||
|
|
||||||
expect(tree).toMatchSnapshot();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Still', () => {
|
|
||||||
it('renders a still avatar', () => {
|
|
||||||
const component = createComponent(<Avatar account={account} size={size} />);
|
|
||||||
const tree = component.toJSON();
|
|
||||||
|
|
||||||
expect(tree).toMatchSnapshot();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// TODO add autoplay test if possible
|
|
||||||
});
|
|
35
app/soapbox/components/__tests__/avatar.test.js
Normal file
35
app/soapbox/components/__tests__/avatar.test.js
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
import { fromJS } from 'immutable';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import { render, screen } from '../../jest/test-helpers';
|
||||||
|
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 an animated avatar', () => {
|
||||||
|
// render(<Avatar account={account} animate size={size} />);
|
||||||
|
|
||||||
|
// expect(screen.getByRole('img').getAttribute('src')).toBe(account.get('avatar'));
|
||||||
|
// });
|
||||||
|
// });
|
||||||
|
|
||||||
|
describe('Still', () => {
|
||||||
|
it('renders a still avatar', () => {
|
||||||
|
render(<Avatar account={account} size={size} />);
|
||||||
|
|
||||||
|
expect(screen.getByRole('img').getAttribute('src')).toBe(account.get('avatar'));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// TODO add autoplay test if possible
|
||||||
|
});
|
|
@ -1,8 +1,7 @@
|
||||||
import { fromJS } from 'immutable';
|
import { fromJS } from 'immutable';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import { createComponent } from 'soapbox/test_helpers';
|
import { render, screen } from '../../jest/test-helpers';
|
||||||
|
|
||||||
import AvatarOverlay from '../avatar_overlay';
|
import AvatarOverlay from '../avatar_overlay';
|
||||||
|
|
||||||
describe('<AvatarOverlay', () => {
|
describe('<AvatarOverlay', () => {
|
||||||
|
@ -23,9 +22,7 @@ describe('<AvatarOverlay', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders a overlay avatar', () => {
|
it('renders a overlay avatar', () => {
|
||||||
const component = createComponent(<AvatarOverlay account={account} friend={friend} />);
|
render(<AvatarOverlay account={account} friend={friend} />);
|
||||||
const tree = component.toJSON();
|
expect(screen.queryAllByRole('img')).toHaveLength(2);
|
||||||
|
|
||||||
expect(tree).toMatchSnapshot();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
|
@ -1,12 +0,0 @@
|
||||||
import React from 'react';
|
|
||||||
import renderer from 'react-test-renderer';
|
|
||||||
|
|
||||||
import Badge from '../badge';
|
|
||||||
|
|
||||||
describe('<Badge />', () => {
|
|
||||||
it('renders correctly', () => {
|
|
||||||
const component = renderer.create(<Badge slug='patron' title='Patron' />);
|
|
||||||
const tree = component.toJSON();
|
|
||||||
expect(tree).toMatchSnapshot();
|
|
||||||
});
|
|
||||||
});
|
|
12
app/soapbox/components/__tests__/badge.test.js
Normal file
12
app/soapbox/components/__tests__/badge.test.js
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import { render, screen } from '../../jest/test-helpers';
|
||||||
|
import Badge from '../badge';
|
||||||
|
|
||||||
|
describe('<Badge />', () => {
|
||||||
|
it('renders correctly', () => {
|
||||||
|
render(<Badge slug='patron' title='Patron' />);
|
||||||
|
|
||||||
|
expect(screen.getByTestId('badge')).toHaveTextContent('Patron');
|
||||||
|
});
|
||||||
|
});
|
|
@ -1,13 +0,0 @@
|
||||||
import React from 'react';
|
|
||||||
|
|
||||||
import { createComponent } from 'soapbox/test_helpers';
|
|
||||||
|
|
||||||
import ColumnBackButton from '../column_back_button';
|
|
||||||
|
|
||||||
describe('<ColumnBackButton />', () => {
|
|
||||||
it('renders correctly', () => {
|
|
||||||
const component = createComponent(<ColumnBackButton />);
|
|
||||||
const tree = component.toJSON();
|
|
||||||
expect(tree).toMatchSnapshot();
|
|
||||||
});
|
|
||||||
});
|
|
12
app/soapbox/components/__tests__/column_back_button.test.js
Normal file
12
app/soapbox/components/__tests__/column_back_button.test.js
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import { render, screen } from '../../jest/test-helpers';
|
||||||
|
import ColumnBackButton from '../column_back_button';
|
||||||
|
|
||||||
|
describe('<ColumnBackButton />', () => {
|
||||||
|
it('renders correctly', () => {
|
||||||
|
render(<ColumnBackButton />);
|
||||||
|
|
||||||
|
expect(screen.getByRole('button')).toHaveTextContent('Back');
|
||||||
|
});
|
||||||
|
});
|
|
@ -1,16 +1,15 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import { normalizeAccount } from 'soapbox/normalizers';
|
import { normalizeAccount } from 'soapbox/normalizers';
|
||||||
import { createComponent } from 'soapbox/test_helpers';
|
|
||||||
|
|
||||||
|
import { render, screen } from '../../jest/test-helpers';
|
||||||
import DisplayName from '../display_name';
|
import DisplayName from '../display_name';
|
||||||
|
|
||||||
describe('<DisplayName />', () => {
|
describe('<DisplayName />', () => {
|
||||||
it('renders display name + account name', () => {
|
it('renders display name + account name', () => {
|
||||||
const account = normalizeAccount({ acct: 'bar@baz' });
|
const account = normalizeAccount({ acct: 'bar@baz' });
|
||||||
const component = createComponent(<DisplayName account={account} />);
|
render(<DisplayName account={account} />);
|
||||||
const tree = component.toJSON();
|
|
||||||
|
|
||||||
expect(tree).toMatchSnapshot();
|
expect(screen.getByTestId('display-name')).toHaveTextContent('bar@baz');
|
||||||
});
|
});
|
||||||
});
|
});
|
|
@ -1,7 +1,6 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import { createComponent } from 'soapbox/test_helpers';
|
import { render, screen } from '../../jest/test-helpers';
|
||||||
|
|
||||||
import EmojiSelector from '../emoji_selector';
|
import EmojiSelector from '../emoji_selector';
|
||||||
|
|
||||||
describe('<EmojiSelector />', () => {
|
describe('<EmojiSelector />', () => {
|
||||||
|
@ -9,8 +8,8 @@ describe('<EmojiSelector />', () => {
|
||||||
const children = <EmojiSelector />;
|
const children = <EmojiSelector />;
|
||||||
children.__proto__.addEventListener = () => {};
|
children.__proto__.addEventListener = () => {};
|
||||||
|
|
||||||
const component = createComponent(children, {}, true);
|
render(children);
|
||||||
const tree = component.toJSON();
|
|
||||||
expect(tree).toMatchSnapshot();
|
expect(screen.queryAllByRole('button')).toHaveLength(6);
|
||||||
});
|
});
|
||||||
});
|
});
|
|
@ -1,8 +1,7 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { defineMessages } from 'react-intl';
|
import { defineMessages } from 'react-intl';
|
||||||
|
|
||||||
import { createComponent } from 'soapbox/test_helpers';
|
import { render, screen } from '../../jest/test-helpers';
|
||||||
|
|
||||||
import TimelineQueueButtonHeader from '../timeline_queue_button_header';
|
import TimelineQueueButtonHeader from '../timeline_queue_button_header';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
|
@ -10,32 +9,35 @@ const messages = defineMessages({
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('<TimelineQueueButtonHeader />', () => {
|
describe('<TimelineQueueButtonHeader />', () => {
|
||||||
it('renders correctly', () => {
|
it('renders correctly', async() => {
|
||||||
expect(createComponent(
|
render(
|
||||||
<TimelineQueueButtonHeader
|
<TimelineQueueButtonHeader
|
||||||
key='timeline-queue-button-header'
|
key='timeline-queue-button-header'
|
||||||
onClick={() => {}} // eslint-disable-line react/jsx-no-bind
|
onClick={() => {}} // eslint-disable-line react/jsx-no-bind
|
||||||
count={0}
|
count={0}
|
||||||
message={messages.queue}
|
message={messages.queue}
|
||||||
/>,
|
/>,
|
||||||
).toJSON()).toMatchSnapshot();
|
);
|
||||||
|
expect(screen.queryAllByRole('link')).toHaveLength(0);
|
||||||
|
|
||||||
expect(createComponent(
|
render(
|
||||||
<TimelineQueueButtonHeader
|
<TimelineQueueButtonHeader
|
||||||
key='timeline-queue-button-header'
|
key='timeline-queue-button-header'
|
||||||
onClick={() => {}} // eslint-disable-line react/jsx-no-bind
|
onClick={() => {}} // eslint-disable-line react/jsx-no-bind
|
||||||
count={1}
|
count={1}
|
||||||
message={messages.queue}
|
message={messages.queue}
|
||||||
/>,
|
/>,
|
||||||
).toJSON()).toMatchSnapshot();
|
);
|
||||||
|
expect(screen.getByText('Click to see 1 new post', { hidden: true })).toBeInTheDocument();
|
||||||
|
|
||||||
expect(createComponent(
|
render(
|
||||||
<TimelineQueueButtonHeader
|
<TimelineQueueButtonHeader
|
||||||
key='timeline-queue-button-header'
|
key='timeline-queue-button-header'
|
||||||
onClick={() => {}} // eslint-disable-line react/jsx-no-bind
|
onClick={() => {}} // eslint-disable-line react/jsx-no-bind
|
||||||
count={9999999}
|
count={9999999}
|
||||||
message={messages.queue}
|
message={messages.queue}
|
||||||
/>,
|
/>,
|
||||||
).toJSON()).toMatchSnapshot();
|
);
|
||||||
|
expect(screen.getByText('Click to see 9999999 new posts', { hidden: true })).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
});
|
});
|
|
@ -28,7 +28,7 @@ export default class AutosuggestEmoji extends React.PureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='autosuggest-emoji'>
|
<div className='autosuggest-emoji' data-testid='emoji'>
|
||||||
<img
|
<img
|
||||||
className='emojione'
|
className='emojione'
|
||||||
src={url}
|
src={url}
|
||||||
|
|
|
@ -2,7 +2,7 @@ import PropTypes from 'prop-types';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
const Badge = (props: any) => (
|
const Badge = (props: any) => (
|
||||||
<span className={'badge badge--' + props.slug}>{props.title}</span>
|
<span data-testid='badge' className={'badge badge--' + props.slug}>{props.title}</span>
|
||||||
);
|
);
|
||||||
|
|
||||||
Badge.propTypes = {
|
Badge.propTypes = {
|
||||||
|
|
|
@ -72,7 +72,7 @@ class DisplayName extends React.PureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<span className='display-name'>
|
<span className='display-name' data-testid='display-name'>
|
||||||
<HoverRefWrapper accountId={account.get('id')} inline>
|
<HoverRefWrapper accountId={account.get('id')} inline>
|
||||||
{displayName}
|
{displayName}
|
||||||
</HoverRefWrapper>
|
</HoverRefWrapper>
|
||||||
|
|
|
@ -1,72 +0,0 @@
|
||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
||||||
|
|
||||||
exports[`<Button /> adds class "button-secondary" if props.theme="secondary" given 1`] = `
|
|
||||||
<button
|
|
||||||
className="inline-flex items-center border font-medium rounded-full focus:outline-none appearance-none transition-all border-transparent text-primary-700 bg-primary-100 hover:bg-primary-200 focus:ring-primary-500 focus:ring-2 focus:ring-offset-2 px-4 py-2 text-sm"
|
|
||||||
disabled={false}
|
|
||||||
onClick={[Function]}
|
|
||||||
type="button"
|
|
||||||
/>
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`<Button /> renders a button element 1`] = `
|
|
||||||
<button
|
|
||||||
className="inline-flex items-center border font-medium rounded-full focus:outline-none appearance-none transition-all border-transparent text-white bg-accent-500 hover:bg-accent-300 focus:ring-pink-500 focus:ring-2 focus:ring-offset-2 px-4 py-2 text-sm"
|
|
||||||
disabled={false}
|
|
||||||
onClick={[Function]}
|
|
||||||
type="button"
|
|
||||||
/>
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`<Button /> renders a disabled attribute if props.disabled given 1`] = `
|
|
||||||
<button
|
|
||||||
className="inline-flex items-center border font-medium rounded-full focus:outline-none appearance-none transition-all select-none disabled:opacity-50 disabled:cursor-default border-transparent text-white bg-accent-500 hover:bg-accent-300 focus:ring-pink-500 focus:ring-2 focus:ring-offset-2 px-4 py-2 text-sm"
|
|
||||||
disabled={true}
|
|
||||||
onClick={[Function]}
|
|
||||||
type="button"
|
|
||||||
/>
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`<Button /> renders class="button--block" if props.block given 1`] = `
|
|
||||||
<button
|
|
||||||
className="inline-flex items-center border font-medium rounded-full focus:outline-none appearance-none transition-all border-transparent text-white bg-accent-500 hover:bg-accent-300 focus:ring-pink-500 focus:ring-2 focus:ring-offset-2 px-4 py-2 text-sm flex w-full justify-center"
|
|
||||||
disabled={false}
|
|
||||||
onClick={[Function]}
|
|
||||||
type="button"
|
|
||||||
/>
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`<Button /> renders the children 1`] = `
|
|
||||||
<button
|
|
||||||
className="inline-flex items-center border font-medium rounded-full focus:outline-none appearance-none transition-all border-transparent text-white bg-accent-500 hover:bg-accent-300 focus:ring-pink-500 focus:ring-2 focus:ring-offset-2 px-4 py-2 text-sm"
|
|
||||||
disabled={false}
|
|
||||||
onClick={[Function]}
|
|
||||||
type="button"
|
|
||||||
>
|
|
||||||
<p>
|
|
||||||
children
|
|
||||||
</p>
|
|
||||||
</button>
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`<Button /> renders the given text 1`] = `
|
|
||||||
<button
|
|
||||||
className="inline-flex items-center border font-medium rounded-full focus:outline-none appearance-none transition-all border-transparent text-white bg-accent-500 hover:bg-accent-300 focus:ring-pink-500 focus:ring-2 focus:ring-offset-2 px-4 py-2 text-sm"
|
|
||||||
disabled={false}
|
|
||||||
onClick={[Function]}
|
|
||||||
type="button"
|
|
||||||
>
|
|
||||||
foo
|
|
||||||
</button>
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`<Button /> renders the props.text instead of children 1`] = `
|
|
||||||
<button
|
|
||||||
className="inline-flex items-center border font-medium rounded-full focus:outline-none appearance-none transition-all border-transparent text-white bg-accent-500 hover:bg-accent-300 focus:ring-pink-500 focus:ring-2 focus:ring-offset-2 px-4 py-2 text-sm"
|
|
||||||
disabled={false}
|
|
||||||
onClick={[Function]}
|
|
||||||
type="button"
|
|
||||||
>
|
|
||||||
foo
|
|
||||||
</button>
|
|
||||||
`;
|
|
|
@ -1,76 +0,0 @@
|
||||||
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.theme="secondary" given', () => {
|
|
||||||
const component = renderer.create(<Button theme='secondary' />);
|
|
||||||
const tree = component.toJSON();
|
|
||||||
|
|
||||||
expect(tree).toMatchSnapshot();
|
|
||||||
});
|
|
||||||
});
|
|
62
app/soapbox/components/ui/button/__tests__/button.test.tsx
Normal file
62
app/soapbox/components/ui/button/__tests__/button.test.tsx
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import { fireEvent, render, screen } from '../../../../jest/test-helpers';
|
||||||
|
import Button from '../button';
|
||||||
|
|
||||||
|
describe('<Button />', () => {
|
||||||
|
it('renders the given text', () => {
|
||||||
|
const text = 'foo';
|
||||||
|
render(<Button text={text} />);
|
||||||
|
|
||||||
|
expect(screen.getByRole('button')).toHaveTextContent(text);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles click events using the given handler', () => {
|
||||||
|
const handler = jest.fn();
|
||||||
|
render(<Button onClick={handler} />);
|
||||||
|
|
||||||
|
fireEvent.click(screen.getByRole('button'));
|
||||||
|
expect(handler.mock.calls.length).toEqual(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not handle click events if props.disabled given', () => {
|
||||||
|
const handler = jest.fn();
|
||||||
|
render(<Button onClick={handler} disabled />);
|
||||||
|
|
||||||
|
fireEvent.click(screen.getByRole('button'));
|
||||||
|
expect(handler.mock.calls.length).toEqual(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders a disabled attribute if props.disabled given', () => {
|
||||||
|
render(<Button disabled />);
|
||||||
|
|
||||||
|
expect(screen.getByRole('button')).toBeDisabled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders the children', () => {
|
||||||
|
render(<Button><p>children</p></Button>);
|
||||||
|
|
||||||
|
expect(screen.getByRole('button')).toHaveTextContent('children');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders the props.text instead of children', () => {
|
||||||
|
const text = 'foo';
|
||||||
|
const children = <p>children</p>;
|
||||||
|
render(<Button text={text}>{children}</Button>);
|
||||||
|
|
||||||
|
expect(screen.getByRole('button')).toHaveTextContent('foo');
|
||||||
|
expect(screen.getByRole('button')).not.toHaveTextContent('children');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('render full-width button if block prop given', () => {
|
||||||
|
render(<Button block />);
|
||||||
|
|
||||||
|
expect(screen.getByRole('button')).toHaveClass('w-full');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles Theme properly', () => {
|
||||||
|
render(<Button theme='secondary' />);
|
||||||
|
|
||||||
|
expect(screen.getByRole('button')).toHaveClass('bg-primary-100');
|
||||||
|
});
|
||||||
|
});
|
|
@ -64,6 +64,7 @@ const Button = React.forwardRef<HTMLButtonElement, IButton>((props, ref): JSX.El
|
||||||
onClick={handleClick}
|
onClick={handleClick}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
type={type}
|
type={type}
|
||||||
|
data-testid='button'
|
||||||
>
|
>
|
||||||
{renderIcon()}
|
{renderIcon()}
|
||||||
{text || children}
|
{text || children}
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import { createShallowComponent } from 'soapbox/test_helpers';
|
import { render, screen } from '../../../../jest/test-helpers';
|
||||||
|
|
||||||
import { Card, CardBody, CardHeader, CardTitle } from '../card';
|
import { Card, CardBody, CardHeader, CardTitle } from '../card';
|
||||||
|
|
||||||
describe('<Card />', () => {
|
describe('<Card />', () => {
|
||||||
it('renders the CardTitle and CardBody', () => {
|
it('renders the CardTitle and CardBody', () => {
|
||||||
const component = createShallowComponent(
|
render(
|
||||||
<Card>
|
<Card>
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<CardTitle title='Card Title' />
|
<CardTitle title='Card Title' />
|
||||||
|
@ -18,13 +17,13 @@ describe('<Card />', () => {
|
||||||
</Card>,
|
</Card>,
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(component.text()).toContain('Card Title');
|
expect(screen.getByTestId('card-title')).toHaveTextContent('Card Title');
|
||||||
expect(component.text()).toContain('Card Body');
|
expect(screen.getByTestId('card-body')).toHaveTextContent('Card Body');
|
||||||
expect(component.text()).not.toContain('Back');
|
expect(screen.queryByTestId('back-button')).not.toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders the Back Button', () => {
|
it('renders the Back Button', () => {
|
||||||
const component = createShallowComponent(
|
render(
|
||||||
<Card>
|
<Card>
|
||||||
<CardHeader backHref='/'>
|
<CardHeader backHref='/'>
|
||||||
<CardTitle title='Card Title' />
|
<CardTitle title='Card Title' />
|
||||||
|
@ -32,6 +31,6 @@ describe('<Card />', () => {
|
||||||
</Card>,
|
</Card>,
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(component.text()).toContain('Back');
|
expect(screen.getByTestId('back-button')).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
});
|
});
|
|
@ -55,7 +55,7 @@ const CardHeader: React.FC<ICardHeader> = ({ children, backHref, onBackClick }):
|
||||||
return (
|
return (
|
||||||
<Comp {...backAttributes} className='mr-2 text-gray-900 dark:text-gray-100' aria-label={intl.formatMessage(messages.back)}>
|
<Comp {...backAttributes} className='mr-2 text-gray-900 dark:text-gray-100' aria-label={intl.formatMessage(messages.back)}>
|
||||||
<InlineSVG src={require('@tabler/icons/icons/arrow-left.svg')} className='h-6 w-6' />
|
<InlineSVG src={require('@tabler/icons/icons/arrow-left.svg')} className='h-6 w-6' />
|
||||||
<span className='sr-only'>Back</span>
|
<span className='sr-only' data-testid='back-button'>Back</span>
|
||||||
</Comp>
|
</Comp>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -74,11 +74,11 @@ interface ICardTitle {
|
||||||
}
|
}
|
||||||
|
|
||||||
const CardTitle = ({ title }: ICardTitle): JSX.Element => (
|
const CardTitle = ({ title }: ICardTitle): JSX.Element => (
|
||||||
<Text size='xl' weight='bold' tag='h1'>{title}</Text>
|
<Text size='xl' weight='bold' tag='h1' data-testid='card-title'>{title}</Text>
|
||||||
);
|
);
|
||||||
|
|
||||||
const CardBody: React.FC = ({ children }): JSX.Element => (
|
const CardBody: React.FC = ({ children }): JSX.Element => (
|
||||||
<div>{children}</div>
|
<div data-testid='card-body'>{children}</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
export { Card, CardHeader, CardTitle, CardBody };
|
export { Card, CardHeader, CardTitle, CardBody };
|
||||||
|
|
|
@ -1,40 +0,0 @@
|
||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
||||||
|
|
||||||
exports[`<Column /> renders correctly with minimal props 1`] = `
|
|
||||||
<div
|
|
||||||
className="relative"
|
|
||||||
column-type="filled"
|
|
||||||
role="region"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className="space-y-4 bg-white dark:bg-slate-800 sm:shadow-lg dark:sm:shadow-inset overflow-hidden p-4 sm:rounded-xl"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className="mb-4 flex flex-row items-center"
|
|
||||||
>
|
|
||||||
<button
|
|
||||||
aria-label="Back"
|
|
||||||
className="mr-2 text-gray-900 dark:text-gray-100"
|
|
||||||
onClick={[Function]}
|
|
||||||
>
|
|
||||||
<svg
|
|
||||||
id={
|
|
||||||
Object {
|
|
||||||
"process": [Function],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<span
|
|
||||||
className="sr-only"
|
|
||||||
>
|
|
||||||
Back
|
|
||||||
</span>
|
|
||||||
</button>
|
|
||||||
<h1
|
|
||||||
className="text-xl text-gray-900 dark:text-gray-100 font-bold tracking-normal font-sans"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
`;
|
|
|
@ -1,13 +0,0 @@
|
||||||
import React from 'react';
|
|
||||||
|
|
||||||
import { createComponent } from 'soapbox/test_helpers';
|
|
||||||
|
|
||||||
import Column from '../column';
|
|
||||||
|
|
||||||
describe('<Column />', () => {
|
|
||||||
it('renders correctly with minimal props', () => {
|
|
||||||
const component = createComponent(<Column />);
|
|
||||||
const tree = component.toJSON();
|
|
||||||
expect(tree).toMatchSnapshot();
|
|
||||||
});
|
|
||||||
});
|
|
12
app/soapbox/components/ui/column/__tests__/column.test.tsx
Normal file
12
app/soapbox/components/ui/column/__tests__/column.test.tsx
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import { render, screen } from '../../../../jest/test-helpers';
|
||||||
|
import Column from '../column';
|
||||||
|
|
||||||
|
describe('<Column />', () => {
|
||||||
|
it('renders correctly with minimal props', () => {
|
||||||
|
render(<Column />);
|
||||||
|
|
||||||
|
expect(screen.getByRole('button')).toHaveTextContent('Back');
|
||||||
|
});
|
||||||
|
});
|
|
@ -1,61 +0,0 @@
|
||||||
import React from 'react';
|
|
||||||
|
|
||||||
import { createShallowComponent } from 'soapbox/test_helpers';
|
|
||||||
|
|
||||||
jest.mock('uuid', () => ({
|
|
||||||
...jest.requireActual('uuid'),
|
|
||||||
}));
|
|
||||||
|
|
||||||
import FormGroup from '../form-group';
|
|
||||||
|
|
||||||
describe('<FormGroup />', () => {
|
|
||||||
it('connects the label and input', () => {
|
|
||||||
const component = createShallowComponent(
|
|
||||||
<FormGroup labelText='My label'>
|
|
||||||
<input type='text' />
|
|
||||||
</FormGroup>,
|
|
||||||
);
|
|
||||||
const otherComponent = createShallowComponent(
|
|
||||||
<FormGroup labelText='My other label'>
|
|
||||||
<input type='text' />
|
|
||||||
</FormGroup>,
|
|
||||||
);
|
|
||||||
|
|
||||||
const inputId = component.find('input').at(0).prop('id');
|
|
||||||
const labelId = component.find('label').at(0).prop('htmlFor');
|
|
||||||
expect(inputId).toBe(labelId);
|
|
||||||
|
|
||||||
const otherInputId = otherComponent.find('input').at(0).prop('id');
|
|
||||||
expect(otherInputId).not.toBe(inputId);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('renders errors', () => {
|
|
||||||
const component = createShallowComponent(
|
|
||||||
<FormGroup labelText='My label' errors={['is invalid', 'is required']}>
|
|
||||||
<input type='text' />
|
|
||||||
</FormGroup>,
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(component.text()).toContain('is invalid, is required');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('renders label', () => {
|
|
||||||
const component = createShallowComponent(
|
|
||||||
<FormGroup labelText='My label'>
|
|
||||||
<input type='text' />
|
|
||||||
</FormGroup>,
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(component.text()).toContain('My label');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('renders hint', () => {
|
|
||||||
const component = createShallowComponent(
|
|
||||||
<FormGroup labelText='My label' hintText='My hint'>
|
|
||||||
<input type='text' />
|
|
||||||
</FormGroup>,
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(component.text()).toContain('My hint');
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import { render, screen } from '../../../../jest/test-helpers';
|
||||||
|
import FormGroup from '../form-group';
|
||||||
|
|
||||||
|
jest.mock('uuid', () => jest.requireActual('uuid'));
|
||||||
|
|
||||||
|
describe('<FormGroup />', () => {
|
||||||
|
it('connects the label and input', () => {
|
||||||
|
render(
|
||||||
|
<>
|
||||||
|
<div>
|
||||||
|
<FormGroup labelText='My label'>
|
||||||
|
<input type='text' data-testid='winner' />
|
||||||
|
</FormGroup>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<FormGroup labelText='My other label'>
|
||||||
|
<input type='text' />
|
||||||
|
</FormGroup>
|
||||||
|
</div>
|
||||||
|
</>,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(screen.getByLabelText('My label')).toHaveAttribute('data-testid');
|
||||||
|
expect(screen.getByLabelText('My other label')).not.toHaveAttribute('data-testid');
|
||||||
|
expect(screen.queryByTestId('form-group-error')).not.toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders errors', () => {
|
||||||
|
render(
|
||||||
|
<FormGroup labelText='My label' errors={['is invalid', 'is required']}>
|
||||||
|
<input type='text' />
|
||||||
|
</FormGroup>,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(screen.getByTestId('form-group-error')).toHaveTextContent('is invalid');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders label', () => {
|
||||||
|
render(
|
||||||
|
<FormGroup labelText='My label'>
|
||||||
|
<input type='text' />
|
||||||
|
</FormGroup>,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(screen.getByTestId('form-group-label')).toHaveTextContent('My label');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders hint', () => {
|
||||||
|
render(
|
||||||
|
<FormGroup labelText='My label' hintText='My hint'>
|
||||||
|
<input type='text' />
|
||||||
|
</FormGroup>,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(screen.getByTestId('form-group-hint')).toHaveTextContent('My hint');
|
||||||
|
});
|
||||||
|
});
|
|
@ -24,6 +24,7 @@ const FormGroup: React.FC<IFormGroup> = (props) => {
|
||||||
<div>
|
<div>
|
||||||
<label
|
<label
|
||||||
htmlFor={formFieldId}
|
htmlFor={formFieldId}
|
||||||
|
data-testid='form-group-label'
|
||||||
className='block text-sm font-medium text-gray-700 dark:text-gray-400'
|
className='block text-sm font-medium text-gray-700 dark:text-gray-400'
|
||||||
>
|
>
|
||||||
{labelText}
|
{labelText}
|
||||||
|
@ -34,13 +35,16 @@ const FormGroup: React.FC<IFormGroup> = (props) => {
|
||||||
{inputChildren.filter((_, i) => i !== 0)}
|
{inputChildren.filter((_, i) => i !== 0)}
|
||||||
|
|
||||||
{errors?.length > 0 && (
|
{errors?.length > 0 && (
|
||||||
<p className='mt-0.5 text-xs text-danger-900 bg-danger-200 rounded-md inline-block px-2 py-1 relative form-error'>
|
<p
|
||||||
|
data-testid='form-group-error'
|
||||||
|
className='mt-0.5 text-xs text-danger-900 bg-danger-200 rounded-md inline-block px-2 py-1 relative form-error'
|
||||||
|
>
|
||||||
{errors.join(', ')}
|
{errors.join(', ')}
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{hintText ? (
|
{hintText ? (
|
||||||
<p className='mt-0.5 text-xs text-gray-400'>
|
<p data-testid='form-group-hint' className='mt-0.5 text-xs text-gray-400'>
|
||||||
{hintText}
|
{hintText}
|
||||||
</p>
|
</p>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
|
@ -1,40 +0,0 @@
|
||||||
import React from 'react';
|
|
||||||
|
|
||||||
import { createShallowComponent } from 'soapbox/test_helpers';
|
|
||||||
|
|
||||||
import Form from '../form';
|
|
||||||
|
|
||||||
describe('<Form />', () => {
|
|
||||||
it('renders children', () => {
|
|
||||||
const onSubmitMock = jest.fn();
|
|
||||||
const component = createShallowComponent(
|
|
||||||
<Form onSubmit={onSubmitMock}>children</Form>,
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(component.text()).toContain('children');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('handles onSubmit prop', () => {
|
|
||||||
const onSubmitMock = jest.fn();
|
|
||||||
const component = createShallowComponent(
|
|
||||||
<Form onSubmit={onSubmitMock}>children</Form>,
|
|
||||||
);
|
|
||||||
|
|
||||||
component.find('form').at(0).simulate('submit', {
|
|
||||||
preventDefault: () => {},
|
|
||||||
});
|
|
||||||
expect(onSubmitMock).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('handles disabled prop', () => {
|
|
||||||
const onSubmitMock = jest.fn();
|
|
||||||
const component = createShallowComponent(
|
|
||||||
<Form onSubmit={onSubmitMock} disabled>
|
|
||||||
<button type='submit'>Submit</button>
|
|
||||||
</Form>,
|
|
||||||
);
|
|
||||||
|
|
||||||
component.find('button').at(0).simulate('click');
|
|
||||||
expect(onSubmitMock).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
});
|
|
29
app/soapbox/components/ui/form/__tests__/form.test.tsx
Normal file
29
app/soapbox/components/ui/form/__tests__/form.test.tsx
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import { fireEvent, render, screen } from '../../../../jest/test-helpers';
|
||||||
|
import Form from '../form';
|
||||||
|
|
||||||
|
describe('<Form />', () => {
|
||||||
|
it('renders children', () => {
|
||||||
|
const onSubmitMock = jest.fn();
|
||||||
|
render(
|
||||||
|
<Form onSubmit={onSubmitMock}>children</Form>,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(screen.getByTestId('form')).toHaveTextContent('children');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles onSubmit prop', () => {
|
||||||
|
const onSubmitMock = jest.fn();
|
||||||
|
render(
|
||||||
|
<Form onSubmit={onSubmitMock}>children</Form>,
|
||||||
|
);
|
||||||
|
|
||||||
|
fireEvent.submit(
|
||||||
|
screen.getByTestId('form'), {
|
||||||
|
preventDefault: () => {},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
expect(onSubmitMock).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
|
@ -1,7 +1,6 @@
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
|
|
||||||
interface IForm {
|
interface IForm {
|
||||||
disabled?: boolean,
|
|
||||||
onSubmit?: (event: React.FormEvent) => void,
|
onSubmit?: (event: React.FormEvent) => void,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,7 +14,7 @@ const Form: React.FC<IForm> = ({ onSubmit, children, ...filteredProps }) => {
|
||||||
}, [onSubmit]);
|
}, [onSubmit]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form onSubmit={handleSubmit} className='space-y-4' {...filteredProps}>
|
<form data-testid='form' onSubmit={handleSubmit} className='space-y-4' {...filteredProps}>
|
||||||
{children}
|
{children}
|
||||||
</form>
|
</form>
|
||||||
);
|
);
|
||||||
|
|
|
@ -3,7 +3,7 @@ import React from 'react';
|
||||||
import InlineSVG from 'react-inlinesvg';
|
import InlineSVG from 'react-inlinesvg';
|
||||||
import { defineMessages, useIntl } from 'react-intl';
|
import { defineMessages, useIntl } from 'react-intl';
|
||||||
|
|
||||||
import Icon from '../../icon';
|
import Icon from '../icon/icon';
|
||||||
import Tooltip from '../tooltip/tooltip';
|
import Tooltip from '../tooltip/tooltip';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
|
|
|
@ -19,7 +19,7 @@ const AuthLayout = () => (
|
||||||
<main className='relative flex flex-col h-screen'>
|
<main className='relative flex flex-col h-screen'>
|
||||||
<header className='pt-10 flex justify-center relative'>
|
<header className='pt-10 flex justify-center relative'>
|
||||||
<Link to='/' className='cursor-pointer'>
|
<Link to='/' className='cursor-pointer'>
|
||||||
<img src='/instance/images/truth-logo.svg' alt='Logo' class='h-7' />
|
<img src='/instance/images/truth-logo.svg' alt='Logo' className='h-7' />
|
||||||
</Link>
|
</Link>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
|
|
|
@ -1,27 +0,0 @@
|
||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
||||||
|
|
||||||
exports[`<CaptchaField /> renders null by default 1`] = `null`;
|
|
||||||
|
|
||||||
exports[`<NativeCaptchaField /> renders correctly 1`] = `
|
|
||||||
<div
|
|
||||||
className="captcha"
|
|
||||||
>
|
|
||||||
<img
|
|
||||||
alt="captcha"
|
|
||||||
src="data:image/png;base64,..."
|
|
||||||
/>
|
|
||||||
<div
|
|
||||||
className="input required"
|
|
||||||
>
|
|
||||||
<input
|
|
||||||
autoCapitalize="off"
|
|
||||||
autoComplete="off"
|
|
||||||
autoCorrect="off"
|
|
||||||
onChange={[Function]}
|
|
||||||
placeholder="Enter the pictured text"
|
|
||||||
required={true}
|
|
||||||
type="text"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
`;
|
|
|
@ -1,267 +0,0 @@
|
||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
||||||
|
|
||||||
exports[`<LoginForm /> renders for Mastodon 1`] = `
|
|
||||||
<div>
|
|
||||||
<div
|
|
||||||
className="pb-4 sm:pb-10 mb-4 border-b border-gray-200 border-solid -mx-4 sm:-mx-10"
|
|
||||||
>
|
|
||||||
<h1
|
|
||||||
className="text-center font-bold text-2xl"
|
|
||||||
>
|
|
||||||
Sign In
|
|
||||||
</h1>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className="sm:pt-10 sm:w-2/3 md:w-1/2 mx-auto"
|
|
||||||
>
|
|
||||||
<form
|
|
||||||
className="space-y-4"
|
|
||||||
onSubmit={[Function]}
|
|
||||||
>
|
|
||||||
<div>
|
|
||||||
<label
|
|
||||||
className="block text-sm font-medium text-gray-700 dark:text-gray-400"
|
|
||||||
htmlFor="field-1"
|
|
||||||
>
|
|
||||||
Email address
|
|
||||||
</label>
|
|
||||||
<div
|
|
||||||
className="mt-1 dark:text-white"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className="mt-1 relative rounded-md shadow-sm"
|
|
||||||
>
|
|
||||||
<input
|
|
||||||
aria-label="Email address"
|
|
||||||
autoCapitalize="off"
|
|
||||||
autoComplete="off"
|
|
||||||
autoCorrect="off"
|
|
||||||
className="dark:bg-slate-800 block w-full sm:text-sm border-gray-300 dark:border-gray-600 rounded-md focus:ring-indigo-500 focus:border-indigo-500"
|
|
||||||
id="field-1"
|
|
||||||
name="username"
|
|
||||||
placeholder="Email address"
|
|
||||||
required={true}
|
|
||||||
type="text"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label
|
|
||||||
className="block text-sm font-medium text-gray-700 dark:text-gray-400"
|
|
||||||
htmlFor="field-1"
|
|
||||||
>
|
|
||||||
Password
|
|
||||||
</label>
|
|
||||||
<div
|
|
||||||
className="mt-1 dark:text-white"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className="mt-1 relative rounded-md shadow-sm"
|
|
||||||
>
|
|
||||||
<input
|
|
||||||
aria-label="Password"
|
|
||||||
autoCapitalize="off"
|
|
||||||
autoComplete="off"
|
|
||||||
autoCorrect="off"
|
|
||||||
className="dark:bg-slate-800 block w-full sm:text-sm border-gray-300 dark:border-gray-600 rounded-md focus:ring-indigo-500 focus:border-indigo-500 pr-7"
|
|
||||||
id="field-1"
|
|
||||||
name="password"
|
|
||||||
placeholder="Password"
|
|
||||||
required={true}
|
|
||||||
type="password"
|
|
||||||
/>
|
|
||||||
<div
|
|
||||||
className="absolute inset-y-0 right-0 flex items-center"
|
|
||||||
data-reach-tooltip-trigger=""
|
|
||||||
data-state="tooltip-hidden"
|
|
||||||
onBlur={[Function]}
|
|
||||||
onFocus={[Function]}
|
|
||||||
onKeyDown={[Function]}
|
|
||||||
onMouseDown={[Function]}
|
|
||||||
onMouseEnter={[Function]}
|
|
||||||
onMouseLeave={[Function]}
|
|
||||||
onMouseMove={[Function]}
|
|
||||||
onPointerDown={[Function]}
|
|
||||||
onPointerEnter={[Function]}
|
|
||||||
onPointerLeave={[Function]}
|
|
||||||
onPointerMove={[Function]}
|
|
||||||
>
|
|
||||||
<button
|
|
||||||
className="text-gray-400 hover:text-gray-500 h-full px-2 focus:ring-primary-500 focus:ring-2"
|
|
||||||
onClick={[Function]}
|
|
||||||
tabIndex={-1}
|
|
||||||
type="button"
|
|
||||||
>
|
|
||||||
<svg
|
|
||||||
id={
|
|
||||||
Object {
|
|
||||||
"process": [Function],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<p
|
|
||||||
className="mt-0.5 text-xs text-gray-400"
|
|
||||||
>
|
|
||||||
<a
|
|
||||||
className="hover:underline"
|
|
||||||
href="/reset-password"
|
|
||||||
onClick={[Function]}
|
|
||||||
>
|
|
||||||
Trouble logging in?
|
|
||||||
</a>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className="flex justify-end space-x-2"
|
|
||||||
>
|
|
||||||
<button
|
|
||||||
className="inline-flex items-center border font-medium rounded-full focus:outline-none appearance-none transition-all border-transparent text-white bg-primary-600 hover:bg-primary-700 focus:ring-primary-500 focus:ring-2 focus:ring-offset-2 px-4 py-2 text-sm"
|
|
||||||
disabled={false}
|
|
||||||
onClick={[Function]}
|
|
||||||
type="submit"
|
|
||||||
>
|
|
||||||
Sign in
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`<LoginForm /> renders for Pleroma 1`] = `
|
|
||||||
<div>
|
|
||||||
<div
|
|
||||||
className="pb-4 sm:pb-10 mb-4 border-b border-gray-200 border-solid -mx-4 sm:-mx-10"
|
|
||||||
>
|
|
||||||
<h1
|
|
||||||
className="text-center font-bold text-2xl"
|
|
||||||
>
|
|
||||||
Sign In
|
|
||||||
</h1>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className="sm:pt-10 sm:w-2/3 md:w-1/2 mx-auto"
|
|
||||||
>
|
|
||||||
<form
|
|
||||||
className="space-y-4"
|
|
||||||
onSubmit={[Function]}
|
|
||||||
>
|
|
||||||
<div>
|
|
||||||
<label
|
|
||||||
className="block text-sm font-medium text-gray-700 dark:text-gray-400"
|
|
||||||
htmlFor="field-1"
|
|
||||||
>
|
|
||||||
Email address
|
|
||||||
</label>
|
|
||||||
<div
|
|
||||||
className="mt-1 dark:text-white"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className="mt-1 relative rounded-md shadow-sm"
|
|
||||||
>
|
|
||||||
<input
|
|
||||||
aria-label="Email address"
|
|
||||||
autoCapitalize="off"
|
|
||||||
autoComplete="off"
|
|
||||||
autoCorrect="off"
|
|
||||||
className="dark:bg-slate-800 block w-full sm:text-sm border-gray-300 dark:border-gray-600 rounded-md focus:ring-indigo-500 focus:border-indigo-500"
|
|
||||||
id="field-1"
|
|
||||||
name="username"
|
|
||||||
placeholder="Email address"
|
|
||||||
required={true}
|
|
||||||
type="text"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label
|
|
||||||
className="block text-sm font-medium text-gray-700 dark:text-gray-400"
|
|
||||||
htmlFor="field-1"
|
|
||||||
>
|
|
||||||
Password
|
|
||||||
</label>
|
|
||||||
<div
|
|
||||||
className="mt-1 dark:text-white"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className="mt-1 relative rounded-md shadow-sm"
|
|
||||||
>
|
|
||||||
<input
|
|
||||||
aria-label="Password"
|
|
||||||
autoCapitalize="off"
|
|
||||||
autoComplete="off"
|
|
||||||
autoCorrect="off"
|
|
||||||
className="dark:bg-slate-800 block w-full sm:text-sm border-gray-300 dark:border-gray-600 rounded-md focus:ring-indigo-500 focus:border-indigo-500 pr-7"
|
|
||||||
id="field-1"
|
|
||||||
name="password"
|
|
||||||
placeholder="Password"
|
|
||||||
required={true}
|
|
||||||
type="password"
|
|
||||||
/>
|
|
||||||
<div
|
|
||||||
className="absolute inset-y-0 right-0 flex items-center"
|
|
||||||
data-reach-tooltip-trigger=""
|
|
||||||
data-state="tooltip-hidden"
|
|
||||||
onBlur={[Function]}
|
|
||||||
onFocus={[Function]}
|
|
||||||
onKeyDown={[Function]}
|
|
||||||
onMouseDown={[Function]}
|
|
||||||
onMouseEnter={[Function]}
|
|
||||||
onMouseLeave={[Function]}
|
|
||||||
onMouseMove={[Function]}
|
|
||||||
onPointerDown={[Function]}
|
|
||||||
onPointerEnter={[Function]}
|
|
||||||
onPointerLeave={[Function]}
|
|
||||||
onPointerMove={[Function]}
|
|
||||||
>
|
|
||||||
<button
|
|
||||||
className="text-gray-400 hover:text-gray-500 h-full px-2 focus:ring-primary-500 focus:ring-2"
|
|
||||||
onClick={[Function]}
|
|
||||||
tabIndex={-1}
|
|
||||||
type="button"
|
|
||||||
>
|
|
||||||
<svg
|
|
||||||
id={
|
|
||||||
Object {
|
|
||||||
"process": [Function],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<p
|
|
||||||
className="mt-0.5 text-xs text-gray-400"
|
|
||||||
>
|
|
||||||
<a
|
|
||||||
className="hover:underline"
|
|
||||||
href="/reset-password"
|
|
||||||
onClick={[Function]}
|
|
||||||
>
|
|
||||||
Trouble logging in?
|
|
||||||
</a>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className="flex justify-end space-x-2"
|
|
||||||
>
|
|
||||||
<button
|
|
||||||
className="inline-flex items-center border font-medium rounded-full focus:outline-none appearance-none transition-all border-transparent text-white bg-primary-600 hover:bg-primary-700 focus:ring-primary-500 focus:ring-2 focus:ring-offset-2 px-4 py-2 text-sm"
|
|
||||||
disabled={false}
|
|
||||||
onClick={[Function]}
|
|
||||||
type="submit"
|
|
||||||
>
|
|
||||||
Sign in
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
`;
|
|
|
@ -1,135 +0,0 @@
|
||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
||||||
|
|
||||||
exports[`<LoginPage /> renders correctly on load 1`] = `
|
|
||||||
<div>
|
|
||||||
<div
|
|
||||||
className="pb-4 sm:pb-10 mb-4 border-b border-gray-200 border-solid -mx-4 sm:-mx-10"
|
|
||||||
>
|
|
||||||
<h1
|
|
||||||
className="text-center font-bold text-2xl"
|
|
||||||
>
|
|
||||||
Sign In
|
|
||||||
</h1>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className="sm:pt-10 sm:w-2/3 md:w-1/2 mx-auto"
|
|
||||||
>
|
|
||||||
<form
|
|
||||||
className="space-y-4"
|
|
||||||
disabled={false}
|
|
||||||
onSubmit={[Function]}
|
|
||||||
>
|
|
||||||
<div>
|
|
||||||
<label
|
|
||||||
className="block text-sm font-medium text-gray-700 dark:text-gray-400"
|
|
||||||
htmlFor="field-1"
|
|
||||||
>
|
|
||||||
Email address
|
|
||||||
</label>
|
|
||||||
<div
|
|
||||||
className="mt-1 dark:text-white"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className="mt-1 relative rounded-md shadow-sm"
|
|
||||||
>
|
|
||||||
<input
|
|
||||||
aria-label="Email address"
|
|
||||||
autoCapitalize="off"
|
|
||||||
autoComplete="off"
|
|
||||||
autoCorrect="off"
|
|
||||||
className="dark:bg-slate-800 block w-full sm:text-sm border-gray-300 dark:border-gray-600 rounded-md focus:ring-indigo-500 focus:border-indigo-500"
|
|
||||||
id="field-1"
|
|
||||||
name="username"
|
|
||||||
placeholder="Email address"
|
|
||||||
required={true}
|
|
||||||
type="text"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label
|
|
||||||
className="block text-sm font-medium text-gray-700 dark:text-gray-400"
|
|
||||||
htmlFor="field-1"
|
|
||||||
>
|
|
||||||
Password
|
|
||||||
</label>
|
|
||||||
<div
|
|
||||||
className="mt-1 dark:text-white"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className="mt-1 relative rounded-md shadow-sm"
|
|
||||||
>
|
|
||||||
<input
|
|
||||||
aria-label="Password"
|
|
||||||
autoCapitalize="off"
|
|
||||||
autoComplete="off"
|
|
||||||
autoCorrect="off"
|
|
||||||
className="dark:bg-slate-800 block w-full sm:text-sm border-gray-300 dark:border-gray-600 rounded-md focus:ring-indigo-500 focus:border-indigo-500 pr-7"
|
|
||||||
id="field-1"
|
|
||||||
name="password"
|
|
||||||
placeholder="Password"
|
|
||||||
required={true}
|
|
||||||
type="password"
|
|
||||||
/>
|
|
||||||
<div
|
|
||||||
className="absolute inset-y-0 right-0 flex items-center"
|
|
||||||
data-reach-tooltip-trigger=""
|
|
||||||
data-state="tooltip-hidden"
|
|
||||||
onBlur={[Function]}
|
|
||||||
onFocus={[Function]}
|
|
||||||
onKeyDown={[Function]}
|
|
||||||
onMouseDown={[Function]}
|
|
||||||
onMouseEnter={[Function]}
|
|
||||||
onMouseLeave={[Function]}
|
|
||||||
onMouseMove={[Function]}
|
|
||||||
onPointerDown={[Function]}
|
|
||||||
onPointerEnter={[Function]}
|
|
||||||
onPointerLeave={[Function]}
|
|
||||||
onPointerMove={[Function]}
|
|
||||||
>
|
|
||||||
<button
|
|
||||||
className="text-gray-400 hover:text-gray-500 h-full px-2 focus:ring-primary-500 focus:ring-2"
|
|
||||||
onClick={[Function]}
|
|
||||||
tabIndex={-1}
|
|
||||||
type="button"
|
|
||||||
>
|
|
||||||
<svg
|
|
||||||
id={
|
|
||||||
Object {
|
|
||||||
"process": [Function],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<p
|
|
||||||
className="mt-0.5 text-xs text-gray-400"
|
|
||||||
>
|
|
||||||
<a
|
|
||||||
className="hover:underline"
|
|
||||||
href="/reset-password"
|
|
||||||
onClick={[Function]}
|
|
||||||
>
|
|
||||||
Trouble logging in?
|
|
||||||
</a>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className="flex justify-end space-x-2"
|
|
||||||
>
|
|
||||||
<button
|
|
||||||
className="inline-flex items-center border font-medium rounded-full focus:outline-none appearance-none transition-all border-transparent text-white bg-primary-600 hover:bg-primary-700 focus:ring-primary-500 focus:ring-2 focus:ring-offset-2 px-4 py-2 text-sm"
|
|
||||||
disabled={false}
|
|
||||||
onClick={[Function]}
|
|
||||||
type="submit"
|
|
||||||
>
|
|
||||||
Sign in
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
`;
|
|
|
@ -1,16 +1,14 @@
|
||||||
import { Map as ImmutableMap } from 'immutable';
|
import { Map as ImmutableMap } from 'immutable';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import renderer from 'react-test-renderer';
|
|
||||||
|
|
||||||
import { createComponent } from 'soapbox/test_helpers';
|
|
||||||
|
|
||||||
|
import { render, screen } from '../../../../jest/test-helpers';
|
||||||
import CaptchaField, { NativeCaptchaField } from '../captcha';
|
import CaptchaField, { NativeCaptchaField } from '../captcha';
|
||||||
|
|
||||||
describe('<CaptchaField />', () => {
|
describe('<CaptchaField />', () => {
|
||||||
it('renders null by default', () => {
|
it('renders null by default', () => {
|
||||||
expect(createComponent(
|
render(<CaptchaField />);
|
||||||
<CaptchaField />,
|
|
||||||
).toJSON()).toMatchSnapshot();
|
expect(screen.queryAllByRole('textbox')).toHaveLength(0);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -23,11 +21,13 @@ describe('<NativeCaptchaField />', () => {
|
||||||
url: 'data:image/png;base64,...',
|
url: 'data:image/png;base64,...',
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(renderer.create(
|
render(
|
||||||
<NativeCaptchaField
|
<NativeCaptchaField
|
||||||
captcha={captcha}
|
captcha={captcha}
|
||||||
onChange={() => {}} // eslint-disable-line react/jsx-no-bind
|
onChange={() => {}} // eslint-disable-line react/jsx-no-bind
|
||||||
/>,
|
/>,
|
||||||
).toJSON()).toMatchSnapshot();
|
);
|
||||||
|
|
||||||
|
expect(screen.queryAllByRole('textbox')).toHaveLength(1);
|
||||||
});
|
});
|
||||||
});
|
});
|
|
@ -1,31 +0,0 @@
|
||||||
import React from 'react';
|
|
||||||
|
|
||||||
import rootReducer from 'soapbox/reducers';
|
|
||||||
import { createComponent, mockStore } from 'soapbox/test_helpers';
|
|
||||||
|
|
||||||
import LoginForm from '../login_form';
|
|
||||||
|
|
||||||
describe('<LoginForm />', () => {
|
|
||||||
|
|
||||||
it('renders for Pleroma', () => {
|
|
||||||
const state = rootReducer(undefined, {})
|
|
||||||
.update('instance', instance => instance.set('version', '2.7.2 (compatible; Pleroma 2.3.0)'));
|
|
||||||
const store = mockStore(state);
|
|
||||||
|
|
||||||
expect(createComponent(
|
|
||||||
<LoginForm />,
|
|
||||||
{ store },
|
|
||||||
).toJSON()).toMatchSnapshot();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('renders for Mastodon', () => {
|
|
||||||
const state = rootReducer(undefined, {})
|
|
||||||
.update('instance', instance => instance.set('version', '3.0.0'));
|
|
||||||
const store = mockStore(state);
|
|
||||||
|
|
||||||
expect(createComponent(
|
|
||||||
<LoginForm />,
|
|
||||||
{ store },
|
|
||||||
).toJSON()).toMatchSnapshot();
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
import { Map as ImmutableMap } from 'immutable';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import { render, screen } from '../../../../jest/test-helpers';
|
||||||
|
import LoginForm from '../login_form';
|
||||||
|
|
||||||
|
describe('<LoginForm />', () => {
|
||||||
|
it('renders for Pleroma', () => {
|
||||||
|
const store = {
|
||||||
|
instance: ImmutableMap({
|
||||||
|
version: '2.7.2 (compatible; Pleroma 2.3.0)',
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
|
render(<LoginForm />, null, store);
|
||||||
|
|
||||||
|
expect(screen.getByRole('heading')).toHaveTextContent('Sign In');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders for Mastodon', () => {
|
||||||
|
const store = {
|
||||||
|
instance: ImmutableMap({
|
||||||
|
version: '3.0.0',
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
|
render(<LoginForm />, null, store);
|
||||||
|
|
||||||
|
expect(screen.getByRole('heading')).toHaveTextContent('Sign In');
|
||||||
|
});
|
||||||
|
});
|
|
@ -1,21 +1,20 @@
|
||||||
|
import { Map as ImmutableMap } from 'immutable';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import rootReducer from 'soapbox/reducers';
|
import { render, screen } from '../../../../jest/test-helpers';
|
||||||
import { createComponent, mockStore } from 'soapbox/test_helpers';
|
|
||||||
|
|
||||||
import LoginPage from '../login_page';
|
import LoginPage from '../login_page';
|
||||||
|
|
||||||
describe('<LoginPage />', () => {
|
describe('<LoginPage />', () => {
|
||||||
it('renders correctly on load', () => {
|
it('renders correctly on load', () => {
|
||||||
const state = rootReducer(undefined, {})
|
const store = {
|
||||||
.set('me', '1234')
|
instance: ImmutableMap({
|
||||||
.update('instance', instance => instance.set('version', '2.7.2 (compatible; Pleroma 2.3.0)'));
|
version: '2.7.2 (compatible; Pleroma 2.3.0)',
|
||||||
const store = mockStore(state);
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
expect(createComponent(
|
render(<LoginPage />, null, store);
|
||||||
<LoginPage />,
|
|
||||||
{ store },
|
expect(screen.getByRole('heading')).toHaveTextContent('Sign In');
|
||||||
).toJSON()).toMatchSnapshot();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// it('renders the OTP form when logIn returns with mfa_required', () => {
|
// it('renders the OTP form when logIn returns with mfa_required', () => {
|
|
@ -1,19 +0,0 @@
|
||||||
import { Map as ImmutableMap } from 'immutable';
|
|
||||||
import React from 'react';
|
|
||||||
|
|
||||||
import { createShallowComponent, mockStore } from 'soapbox/test_helpers';
|
|
||||||
|
|
||||||
import OtpAuthForm from '../otp_auth_form';
|
|
||||||
|
|
||||||
describe('<OtpAuthForm />', () => {
|
|
||||||
it('renders correctly', () => {
|
|
||||||
const store = mockStore(ImmutableMap({ mfa_auth_needed: true }));
|
|
||||||
const component = createShallowComponent(
|
|
||||||
<OtpAuthForm mfa_token={'12345'} />,
|
|
||||||
{ store },
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(component.text()).toContain('OTP Login');
|
|
||||||
expect(component.exists('form')).toBe(true);
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import { render, screen } from '../../../../jest/test-helpers';
|
||||||
|
import OtpAuthForm from '../otp_auth_form';
|
||||||
|
|
||||||
|
describe('<OtpAuthForm />', () => {
|
||||||
|
it('renders correctly', () => {
|
||||||
|
render(<OtpAuthForm mfa_token={'12345'} />);
|
||||||
|
|
||||||
|
expect(screen.getByRole('heading')).toHaveTextContent('OTP Login');
|
||||||
|
expect(screen.getByTestId('form')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
|
@ -1,17 +1,15 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { act } from 'react-dom/test-utils';
|
|
||||||
import { Route, Switch } from 'react-router-dom';
|
import { Route, Switch } from 'react-router-dom';
|
||||||
|
|
||||||
import { __stub } from 'soapbox/api';
|
import { __stub } from 'soapbox/api';
|
||||||
import rootReducer from 'soapbox/reducers';
|
|
||||||
import { createShallowComponent, mockStore } from 'soapbox/test_helpers';
|
|
||||||
|
|
||||||
|
import { fireEvent, render, screen, waitFor } from '../../../../jest/test-helpers';
|
||||||
import PasswordResetConfirm from '../password_reset_confirm';
|
import PasswordResetConfirm from '../password_reset_confirm';
|
||||||
|
|
||||||
const TestableComponent = () => (
|
const TestableComponent = () => (
|
||||||
<Switch>
|
<Switch>
|
||||||
<Route path='/edit' exact><PasswordResetConfirm /></Route>
|
<Route path='/edit' exact><PasswordResetConfirm /></Route>
|
||||||
<Route path='/' exact><span>Homepage</span></Route>
|
<Route path='/' exact><span data-testid='home'>Homepage</span></Route>
|
||||||
</Switch>
|
</Switch>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -22,24 +20,23 @@ describe('<PasswordResetConfirm />', () => {
|
||||||
.reply(200, {});
|
.reply(200, {});
|
||||||
});
|
});
|
||||||
|
|
||||||
const state = rootReducer(undefined, {});
|
render(
|
||||||
const store = mockStore(state);
|
|
||||||
const component = createShallowComponent(
|
|
||||||
<TestableComponent />,
|
<TestableComponent />,
|
||||||
{ store },
|
{},
|
||||||
|
null,
|
||||||
{ initialEntries: ['/edit'] },
|
{ initialEntries: ['/edit'] },
|
||||||
);
|
);
|
||||||
|
|
||||||
await component.find('form').at(0).simulate('submit', {
|
fireEvent.submit(
|
||||||
|
screen.getByTestId('form'), {
|
||||||
preventDefault: () => {},
|
preventDefault: () => {},
|
||||||
});
|
},
|
||||||
await act(async() => {
|
);
|
||||||
await new Promise(resolve => setTimeout(resolve, 0));
|
|
||||||
component.update();
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(component.text()).toContain('Homepage');
|
await waitFor(() => {
|
||||||
expect(component.text()).not.toContain('Expired token');
|
expect(screen.getByTestId('home')).toHaveTextContent('Homepage');
|
||||||
|
expect(screen.queryByTestId('form-group-error')).not.toBeInTheDocument();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('handles failed responses from the API', async() => {
|
it('handles failed responses from the API', async() => {
|
||||||
|
@ -48,23 +45,22 @@ describe('<PasswordResetConfirm />', () => {
|
||||||
.reply(403, {});
|
.reply(403, {});
|
||||||
});
|
});
|
||||||
|
|
||||||
const state = rootReducer(undefined, {});
|
render(
|
||||||
const store = mockStore(state);
|
|
||||||
const component = createShallowComponent(
|
|
||||||
<TestableComponent />,
|
<TestableComponent />,
|
||||||
{ store },
|
{},
|
||||||
|
null,
|
||||||
{ initialEntries: ['/edit'] },
|
{ initialEntries: ['/edit'] },
|
||||||
);
|
);
|
||||||
|
|
||||||
await component.find('form').at(0).simulate('submit', {
|
await fireEvent.submit(
|
||||||
|
screen.getByTestId('form'), {
|
||||||
preventDefault: () => {},
|
preventDefault: () => {},
|
||||||
});
|
},
|
||||||
await act(async() => {
|
);
|
||||||
await new Promise(resolve => setTimeout(resolve, 0));
|
|
||||||
component.update();
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(component.text()).toContain('Expired token');
|
await waitFor(() => {
|
||||||
expect(component.text()).not.toContain('Homepage');
|
expect(screen.queryByTestId('home')).not.toBeInTheDocument();
|
||||||
|
expect(screen.queryByTestId('form-group-error')).toBeInTheDocument();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -30,7 +30,7 @@ const LoginForm = ({ isLoading, handleSubmit }) => {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className='sm:pt-10 sm:w-2/3 md:w-1/2 mx-auto'>
|
<div className='sm:pt-10 sm:w-2/3 md:w-1/2 mx-auto'>
|
||||||
<Form onSubmit={handleSubmit} disabled={isLoading}>
|
<Form onSubmit={handleSubmit}>
|
||||||
<FormGroup labelText={intl.formatMessage(messages.email)}>
|
<FormGroup labelText={intl.formatMessage(messages.email)}>
|
||||||
<Input
|
<Input
|
||||||
aria-label={intl.formatMessage(messages.email)}
|
aria-label={intl.formatMessage(messages.email)}
|
||||||
|
|
|
@ -66,7 +66,7 @@ class OtpAuthForm extends ImmutablePureComponent {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className='sm:pt-10 sm:w-2/3 md:w-1/2 mx-auto'>
|
<div className='sm:pt-10 sm:w-2/3 md:w-1/2 mx-auto'>
|
||||||
<Form onSubmit={this.handleSubmit} disabled={this.state.isLoading}>
|
<Form onSubmit={this.handleSubmit}>
|
||||||
<FormGroup
|
<FormGroup
|
||||||
labelText={intl.formatMessage(messages.otpCodeLabel)}
|
labelText={intl.formatMessage(messages.otpCodeLabel)}
|
||||||
hintText={intl.formatMessage(messages.otpCodeHint)}
|
hintText={intl.formatMessage(messages.otpCodeHint)}
|
||||||
|
|
|
@ -49,7 +49,7 @@ class PasswordReset extends ImmutablePureComponent {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className='sm:pt-10 sm:w-2/3 md:w-1/2 mx-auto'>
|
<div className='sm:pt-10 sm:w-2/3 md:w-1/2 mx-auto'>
|
||||||
<Form onSubmit={this.handleSubmit} disabled={this.state.isLoading}>
|
<Form onSubmit={this.handleSubmit}>
|
||||||
<FormGroup labelText={intl.formatMessage(messages.nicknameOrEmail)}>
|
<FormGroup labelText={intl.formatMessage(messages.nicknameOrEmail)}>
|
||||||
<Input
|
<Input
|
||||||
name='nickname_or_email'
|
name='nickname_or_email'
|
||||||
|
|
|
@ -62,7 +62,7 @@ const PasswordResetConfirm = ({ resetPasswordConfirm }) => {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className='sm:pt-10 sm:w-2/3 md:w-1/2 mx-auto'>
|
<div className='sm:pt-10 sm:w-2/3 md:w-1/2 mx-auto'>
|
||||||
<Form onSubmit={handleSubmit} disabled={isLoading}>
|
<Form onSubmit={handleSubmit}>
|
||||||
<FormGroup labelText='Password' errors={renderErrors()}>
|
<FormGroup labelText='Password' errors={renderErrors()}>
|
||||||
<Input
|
<Input
|
||||||
type='password'
|
type='password'
|
||||||
|
|
|
@ -53,7 +53,7 @@ const DeleteAccount = () => {
|
||||||
{intl.formatMessage(messages.deleteText)}
|
{intl.formatMessage(messages.deleteText)}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<Form onSubmit={handleSubmit} disabled={isLoading}>
|
<Form onSubmit={handleSubmit}>
|
||||||
<FormGroup labelText={intl.formatMessage(messages.passwordFieldLabel)}>
|
<FormGroup labelText={intl.formatMessage(messages.passwordFieldLabel)}>
|
||||||
<Input
|
<Input
|
||||||
type='password'
|
type='password'
|
||||||
|
|
|
@ -183,7 +183,7 @@ class CreateApp extends ImmutablePureComponent {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Column label={intl.formatMessage(messages.heading)} backHref='/developers'>
|
<Column label={intl.formatMessage(messages.heading)} backHref='/developers'>
|
||||||
<Form onSubmit={this.handleSubmit} disabled={isLoading}>
|
<Form onSubmit={this.handleSubmit}>
|
||||||
<FormGroup labelText={<FormattedMessage id='app_create.name_label' defaultMessage='App name' />}>
|
<FormGroup labelText={<FormattedMessage id='app_create.name_label' defaultMessage='App name' />}>
|
||||||
<Input
|
<Input
|
||||||
placeholder={intl.formatMessage(messages.namePlaceholder)}
|
placeholder={intl.formatMessage(messages.namePlaceholder)}
|
||||||
|
@ -220,7 +220,7 @@ class CreateApp extends ImmutablePureComponent {
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
|
|
||||||
<FormActions>
|
<FormActions>
|
||||||
<Button theme='primary' type='submit'>
|
<Button theme='primary' type='submit' disabled={isLoading}>
|
||||||
<FormattedMessage id='app_create.submit' defaultMessage='Create app' />
|
<FormattedMessage id='app_create.submit' defaultMessage='Create app' />
|
||||||
</Button>
|
</Button>
|
||||||
</FormActions>
|
</FormActions>
|
||||||
|
|
|
@ -90,7 +90,7 @@ class SettingsStore extends ImmutablePureComponent {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Column label={intl.formatMessage(messages.heading)} backHref='/developers'>
|
<Column label={intl.formatMessage(messages.heading)} backHref='/developers'>
|
||||||
<Form onSubmit={this.handleSubmit} disabled={!jsonValid || isLoading}>
|
<Form onSubmit={this.handleSubmit}>
|
||||||
<FormGroup
|
<FormGroup
|
||||||
hintText={intl.formatMessage(messages.hint)}
|
hintText={intl.formatMessage(messages.hint)}
|
||||||
errors={jsonValid ? [] : ['is invalid']}
|
errors={jsonValid ? [] : ['is invalid']}
|
||||||
|
|
|
@ -60,7 +60,7 @@ const EditEmail = () => {
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
|
|
||||||
<CardBody>
|
<CardBody>
|
||||||
<Form onSubmit={handleSubmit} disabled={isLoading}>
|
<Form onSubmit={handleSubmit}>
|
||||||
<FormGroup labelText={intl.formatMessage(messages.emailFieldLabel)}>
|
<FormGroup labelText={intl.formatMessage(messages.emailFieldLabel)}>
|
||||||
<Input
|
<Input
|
||||||
placeholder={intl.formatMessage({ id: 'edit_email.placeholder', defaultMessage: 'me@example.com' })}
|
placeholder={intl.formatMessage({ id: 'edit_email.placeholder', defaultMessage: 'me@example.com' })}
|
||||||
|
|
|
@ -59,7 +59,7 @@ const EditPassword = () => {
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
|
|
||||||
<CardBody>
|
<CardBody>
|
||||||
<Form onSubmit={handleSubmit} disabled={isLoading}>
|
<Form onSubmit={handleSubmit}>
|
||||||
<FormGroup labelText={intl.formatMessage(messages.oldPasswordFieldLabel)}>
|
<FormGroup labelText={intl.formatMessage(messages.oldPasswordFieldLabel)}>
|
||||||
<Input
|
<Input
|
||||||
type='password'
|
type='password'
|
||||||
|
|
|
@ -1,103 +0,0 @@
|
||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
||||||
|
|
||||||
exports[`<Checkbox /> renders correctly 1`] = `
|
|
||||||
<div
|
|
||||||
className="input boolean"
|
|
||||||
>
|
|
||||||
<input
|
|
||||||
type="checkbox"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`<FieldsGroup /> renders correctly 1`] = `
|
|
||||||
<div
|
|
||||||
className="fields-group"
|
|
||||||
/>
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`<FileChooser /> renders correctly 1`] = `
|
|
||||||
<div
|
|
||||||
className="input"
|
|
||||||
>
|
|
||||||
<input
|
|
||||||
accept={
|
|
||||||
Array [
|
|
||||||
"image/jpeg",
|
|
||||||
"image/png",
|
|
||||||
"image/gif",
|
|
||||||
"image/webp",
|
|
||||||
]
|
|
||||||
}
|
|
||||||
type="file"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`<InputContainer /> renders correctly 1`] = `
|
|
||||||
<div
|
|
||||||
className="input"
|
|
||||||
/>
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`<RadioGroup /> renders correctly 1`] = `
|
|
||||||
<div
|
|
||||||
className="input with_floating_label radio_buttons"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className="label_input"
|
|
||||||
>
|
|
||||||
<label />
|
|
||||||
<ul />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`<SelectDropdown /> renders correctly 1`] = `
|
|
||||||
<select
|
|
||||||
className="pl-3 pr-10 py-2 text-base border-gray-300 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm rounded-md"
|
|
||||||
>
|
|
||||||
<option
|
|
||||||
value="one"
|
|
||||||
>
|
|
||||||
One
|
|
||||||
</option>
|
|
||||||
<option
|
|
||||||
value="two"
|
|
||||||
>
|
|
||||||
Two
|
|
||||||
</option>
|
|
||||||
<option
|
|
||||||
value="three"
|
|
||||||
>
|
|
||||||
Three
|
|
||||||
</option>
|
|
||||||
</select>
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`<SimpleForm /> renders correctly 1`] = `
|
|
||||||
<form
|
|
||||||
acceptCharset="UTF-8"
|
|
||||||
className="simple_form"
|
|
||||||
method="post"
|
|
||||||
onSubmit={[Function]}
|
|
||||||
/>
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`<SimpleInput /> renders correctly 1`] = `
|
|
||||||
<div
|
|
||||||
className="input"
|
|
||||||
>
|
|
||||||
<input />
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`<TextInput /> renders correctly 1`] = `
|
|
||||||
<div
|
|
||||||
className="input"
|
|
||||||
>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
`;
|
|
|
@ -1,86 +0,0 @@
|
||||||
import React from 'react';
|
|
||||||
import renderer from 'react-test-renderer';
|
|
||||||
|
|
||||||
import {
|
|
||||||
InputContainer,
|
|
||||||
SimpleInput,
|
|
||||||
SimpleForm,
|
|
||||||
FieldsGroup,
|
|
||||||
Checkbox,
|
|
||||||
RadioGroup,
|
|
||||||
SelectDropdown,
|
|
||||||
TextInput,
|
|
||||||
FileChooser,
|
|
||||||
} from '..';
|
|
||||||
|
|
||||||
describe('<InputContainer />', () => {
|
|
||||||
it('renders correctly', () => {
|
|
||||||
expect(renderer.create(
|
|
||||||
<InputContainer />,
|
|
||||||
).toJSON()).toMatchSnapshot();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('<SimpleInput />', () => {
|
|
||||||
it('renders correctly', () => {
|
|
||||||
expect(renderer.create(
|
|
||||||
<SimpleInput />,
|
|
||||||
).toJSON()).toMatchSnapshot();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('<SimpleForm />', () => {
|
|
||||||
it('renders correctly', () => {
|
|
||||||
expect(renderer.create(
|
|
||||||
<SimpleForm />,
|
|
||||||
).toJSON()).toMatchSnapshot();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('<FieldsGroup />', () => {
|
|
||||||
it('renders correctly', () => {
|
|
||||||
expect(renderer.create(
|
|
||||||
<FieldsGroup />,
|
|
||||||
).toJSON()).toMatchSnapshot();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('<Checkbox />', () => {
|
|
||||||
it('renders correctly', () => {
|
|
||||||
expect(renderer.create(
|
|
||||||
<Checkbox />,
|
|
||||||
).toJSON()).toMatchSnapshot();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('<RadioGroup />', () => {
|
|
||||||
it('renders correctly', () => {
|
|
||||||
expect(renderer.create(
|
|
||||||
<RadioGroup />,
|
|
||||||
).toJSON()).toMatchSnapshot();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('<SelectDropdown />', () => {
|
|
||||||
it('renders correctly', () => {
|
|
||||||
expect(renderer.create(
|
|
||||||
<SelectDropdown items={{ one: 'One', two: 'Two', three: 'Three' }} />,
|
|
||||||
).toJSON()).toMatchSnapshot();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('<TextInput />', () => {
|
|
||||||
it('renders correctly', () => {
|
|
||||||
expect(renderer.create(
|
|
||||||
<TextInput />,
|
|
||||||
).toJSON()).toMatchSnapshot();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('<FileChooser />', () => {
|
|
||||||
it('renders correctly', () => {
|
|
||||||
expect(renderer.create(
|
|
||||||
<FileChooser />,
|
|
||||||
).toJSON()).toMatchSnapshot();
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -144,7 +144,7 @@ class DisableOtpForm extends ImmutablePureComponent {
|
||||||
const { isLoading, password } = this.state;
|
const { isLoading, password } = this.state;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Form onSubmit={this.handleSubmit} disabled={isLoading}>
|
<Form onSubmit={this.handleSubmit}>
|
||||||
<Stack>
|
<Stack>
|
||||||
<Text weight='medium'>
|
<Text weight='medium'>
|
||||||
<FormattedMessage id='mfa.otp_enabled_title' defaultMessage='OTP Enabled' />
|
<FormattedMessage id='mfa.otp_enabled_title' defaultMessage='OTP Enabled' />
|
||||||
|
@ -335,7 +335,7 @@ class OtpConfirmForm extends ImmutablePureComponent {
|
||||||
<Stack space={4}>
|
<Stack space={4}>
|
||||||
<hr className='mt-4' />
|
<hr className='mt-4' />
|
||||||
|
|
||||||
<Form onSubmit={this.handleSubmit} disabled={isLoading}>
|
<Form onSubmit={this.handleSubmit}>
|
||||||
<Stack>
|
<Stack>
|
||||||
<Text weight='semibold' size='lg'>
|
<Text weight='semibold' size='lg'>
|
||||||
1. <FormattedMessage id='mfa.mfa_setup_scan_title' defaultMessage='Scan' />
|
1. <FormattedMessage id='mfa.mfa_setup_scan_title' defaultMessage='Scan' />
|
||||||
|
|
|
@ -1,29 +0,0 @@
|
||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
||||||
|
|
||||||
exports[`<ComposeButton /> renders a button element 1`] = `
|
|
||||||
<div
|
|
||||||
className="mt-4"
|
|
||||||
>
|
|
||||||
<button
|
|
||||||
className="inline-flex items-center border font-medium rounded-full focus:outline-none appearance-none transition-all border-transparent text-white bg-accent-500 hover:bg-accent-300 focus:ring-pink-500 focus:ring-2 focus:ring-offset-2 px-6 py-3 text-base flex w-full justify-center"
|
|
||||||
disabled={false}
|
|
||||||
onClick={[Function]}
|
|
||||||
type="button"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className="svg-icon mr-2"
|
|
||||||
>
|
|
||||||
<svg
|
|
||||||
id={
|
|
||||||
Object {
|
|
||||||
"process": [Function],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<span>
|
|
||||||
Compose
|
|
||||||
</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
`;
|
|
|
@ -1,26 +1,39 @@
|
||||||
|
import { fireEvent, render, screen } from '@testing-library/react';
|
||||||
import { Map as ImmutableMap } from 'immutable';
|
import { Map as ImmutableMap } from 'immutable';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { IntlProvider } from 'react-intl';
|
||||||
|
import { Provider } from 'react-redux';
|
||||||
|
import '@testing-library/jest-dom';
|
||||||
|
|
||||||
import { MODAL_OPEN } from 'soapbox/actions/modals';
|
import { MODAL_OPEN } from 'soapbox/actions/modals';
|
||||||
|
import { mockStore } from 'soapbox/jest/test-helpers';
|
||||||
import rootReducer from 'soapbox/reducers';
|
import rootReducer from 'soapbox/reducers';
|
||||||
import { createComponent, mockStore } from 'soapbox/test_helpers';
|
|
||||||
|
|
||||||
import ComposeButton from '../compose-button';
|
import ComposeButton from '../compose-button';
|
||||||
|
|
||||||
|
const store = mockStore(rootReducer(ImmutableMap(), {}));
|
||||||
|
const renderComposeButton = () => {
|
||||||
|
render(
|
||||||
|
<Provider store={store}>
|
||||||
|
<IntlProvider locale='en'>
|
||||||
|
<ComposeButton />
|
||||||
|
</IntlProvider>
|
||||||
|
</Provider>,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
describe('<ComposeButton />', () => {
|
describe('<ComposeButton />', () => {
|
||||||
it('renders a button element', () => {
|
it('renders a button element', () => {
|
||||||
const component = createComponent(<ComposeButton />);
|
renderComposeButton();
|
||||||
const tree = component.toJSON();
|
|
||||||
|
|
||||||
expect(tree).toMatchSnapshot();
|
expect(screen.getByRole('button')).toHaveTextContent('Compose');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('dispatches the MODAL_OPEN action', () => {
|
it('dispatches the MODAL_OPEN action', () => {
|
||||||
const store = mockStore(rootReducer(ImmutableMap(), {}));
|
renderComposeButton();
|
||||||
const component = createComponent(<ComposeButton />, { store });
|
|
||||||
|
|
||||||
expect(store.getActions().length).toEqual(0);
|
expect(store.getActions().length).toEqual(0);
|
||||||
component.root.findByType('button').props.onClick();
|
fireEvent.click(screen.getByRole('button'));
|
||||||
expect(store.getActions()[0].type).toEqual(MODAL_OPEN);
|
expect(store.getActions()[0].type).toEqual(MODAL_OPEN);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -8,7 +8,7 @@ import { dismissAlert } from '../../../actions/alerts';
|
||||||
import { getAlerts } from '../../../selectors';
|
import { getAlerts } from '../../../selectors';
|
||||||
|
|
||||||
const CustomNotificationStack = (props) => (
|
const CustomNotificationStack = (props) => (
|
||||||
<div role='assertive' className='z-1000 fixed inset-0 flex items-end px-4 py-6 pointer-events-none sm:p-6 sm:items-start'>
|
<div role='assertive' data-testid='toast' className='z-1000 fixed inset-0 flex items-end px-4 py-6 pointer-events-none sm:p-6 sm:items-start'>
|
||||||
<NotificationStack {...props} />
|
<NotificationStack {...props} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -5,7 +5,7 @@ import {
|
||||||
ALERT_DISMISS,
|
ALERT_DISMISS,
|
||||||
ALERT_CLEAR,
|
ALERT_CLEAR,
|
||||||
} from 'soapbox/actions/alerts';
|
} from 'soapbox/actions/alerts';
|
||||||
import { applyActions } from 'soapbox/test_helpers';
|
import { applyActions } from 'soapbox/jest/test-helpers';
|
||||||
|
|
||||||
import reducer from '../alerts';
|
import reducer from '../alerts';
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,7 @@ import {
|
||||||
NOTIFICATIONS_MARK_READ_REQUEST,
|
NOTIFICATIONS_MARK_READ_REQUEST,
|
||||||
} from 'soapbox/actions/notifications';
|
} from 'soapbox/actions/notifications';
|
||||||
import { TIMELINE_DELETE } from 'soapbox/actions/timelines';
|
import { TIMELINE_DELETE } from 'soapbox/actions/timelines';
|
||||||
import { applyActions } from 'soapbox/test_helpers';
|
import { applyActions } from 'soapbox/jest/test-helpers';
|
||||||
|
|
||||||
import reducer from '../notifications';
|
import reducer from '../notifications';
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue