Skip to content
15 changes: 13 additions & 2 deletions 03 Tests samples/src/components/MessageList/MessageList.less
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

.messages-table{
border: @tableBorder;
width: 80%;
width: 100%;
border-collapse: collapse;
td, th {
border: @tableBorder;
Expand All @@ -26,4 +26,15 @@
}
}
}
};
};

.messages-table-container {
width: 80%;
margin-left: 20px;
}

.context-menu-info {
padding: 8px;
border: @tableBorder;
position: absolute;
}
56 changes: 38 additions & 18 deletions 03 Tests samples/src/components/MessageList/MessageList.test.tsx
Original file line number Diff line number Diff line change
@@ -1,47 +1,67 @@
import * as React from 'react';
import { shallow } from 'enzyme';
import { shallow } from 'enzyme';
import { configure } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import {MessageList} from './MessageList';
import { MessageList } from './MessageList';

describe('Message List component test', () => {
configure({ adapter: new Adapter() });

let component;

const messages = [
{
id: 1,
subject: 'Hello world',
body: 'Hello world',
},
];

beforeEach(() => {
component = shallow(< MessageList messages={[]}/>);
component = shallow(<MessageList messages={[]} />);
});

afterEach(() => {
jest.clearAllMocks();
});

it('should render a table', () =>{
it('should render a table', () => {
expect(component.find('table')).toHaveLength(1);
});

it('should render two th', () =>{
it('should render two th', () => {
expect(component.find('th')).toHaveLength(2);
});

it('should render a thead', () =>{
it('should render a thead', () => {
expect(component.find('thead')).toHaveLength(1);
});

it('should render a tbody', () =>{
it('should render a tbody', () => {
expect(component.find('tbody')).toHaveLength(1);
});

it('should render none td', () =>{
it('should render none td', () => {
expect(component.find('td')).toHaveLength(0);
});

it('should render two td', () => {
let messages = [
{
id: 1,
subject: 'Hello world',
body: 'Hello world'
}
];
component = shallow(< MessageList messages={messages}/>);
component = shallow(<MessageList messages={messages} />);
expect(component.find('td')).toHaveLength(2);
});
});

it('should alert mousedown on mouse down on the tr', () => {
jest.spyOn(window, 'alert').mockImplementation(() => {});
component = shallow(<MessageList messages={messages} />);
const bodyMessages = component.find('tr').at(1);
bodyMessages.simulate('mousedown', { type: 'mousedown' });
expect(window.alert).toBeCalledWith('mousedown');
});

it('should alert mouseup on mouse up on the tr', () => {
jest.spyOn(window, 'alert').mockImplementation(() => {});
component = shallow(<MessageList messages={messages} />);
const bodyMessages = component.find('tr').at(1);
bodyMessages.simulate('mouseup', { type: 'mouseup' });
expect(window.alert).toBeCalledWith('mouseup');
});
});
81 changes: 64 additions & 17 deletions 03 Tests samples/src/components/MessageList/MessageList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,71 @@ import './MessageList.less';
import { Message } from '../../model';

interface MessageListProps {
messages: Message[],
messages: Message[];
}

export const MessageList = (props: MessageListProps) => {
return (<table className="messages-table">
<thead>
<tr>
<th>Subject</th>
<th>Body</th>
</tr>
</thead>
<tbody>
{props.messages.map(message => {
return (<tr key={message.id}>
<td>{message.subject}</td>
<td>{message.body}</td>
</tr>);
})}
</tbody>
</table>);
const [clickPosition, setClickPosition] = React.useState({
clientX: 0,
clientY: 0,
});
const [showContextMenu, setShowContextMenu] = React.useState(false);

const handleContextMenu = (event: React.MouseEvent) => {
setClickPosition({ clientX: event.clientX, clientY: event.clientY });
event.preventDefault();
document.addEventListener('mousedown', handleClickAfterContextMenuOpen);
setShowContextMenu(true);
};

const handleOnMouse = (event: React.MouseEvent) => {
event.type === 'mousedown' ? alert('mousedown') : alert('mouseup');
};

const handleClickAfterContextMenuOpen = (e: MouseEvent) => {
// Only if the left button is clicked - number 1
// We need to perform this check since this method will also get called when right-clicking
if (e.which === 1) {
document.removeEventListener(
'mousedown',
handleClickAfterContextMenuOpen
);
setTimeout(() => setShowContextMenu(false), 100);
}
};

return (
<div onContextMenu={handleContextMenu} className="messages-table-container">
<table className="messages-table">
<thead>
<tr>
<th>Subject</th>
<th>Body</th>
</tr>
</thead>
<tbody>
{props.messages.map((message) => (
<tr
key={message.id}
onMouseDown={handleOnMouse}
onMouseUp={handleOnMouse}
>
<td>{message.subject}</td>
<td>{message.body}</td>
</tr>
))}
</tbody>
</table>
{showContextMenu && (
<div
className="context-menu-info"
style={{ top: clickPosition.clientY, left: clickPosition.clientX }}
>
<div>
{`Context menu top-position:${clickPosition.clientY} left-position:${clickPosition.clientX}`}
</div>
</div>
)}
</div>
);
};
40 changes: 40 additions & 0 deletions 03 Tests samples/src/components/MessageList/onContextMenu.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import * as React from 'react';
import { shallow } from 'enzyme';
import { configure } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please try to do this generic to only acces as config file and not need to call and configure this in every test file

import { MessageList } from './MessageList';

describe('Message List component test', () => {
configure({ adapter: new Adapter() });

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The same as before


let component;

beforeEach(() => {
component = shallow(<MessageList messages={[]} />);
});

afterEach(() => {
jest.clearAllMocks();
});

it('should open a context-menu on right clicking on the table', () => {
const preventDefault = jest.fn();
component
.find('div')
.at(0)
.simulate('contextMenu', { clientX: 969, clientY: 140, preventDefault });
expect(component.find('.context-menu-info')).toHaveLength(1);
});
// This test passes due to the setTimeout function, we should work over this.
it('should close context menu', () => {
const preventDefault = jest.fn();
component
.find('div')
.at(0)
.simulate('contextMenu', { clientX: 969, clientY: 140, preventDefault });
component.find('div').at(0).simulate('mousedown', { which: 1 });
setTimeout(() => {
expect(component.find('.context-menu-info')).toHaveLength(0);
}, 150);
});
});