Skip to content
This repository was archived by the owner on Jul 12, 2023. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48,674 changes: 33,443 additions & 15,231 deletions package-lock.json

Large diffs are not rendered by default.

47 changes: 23 additions & 24 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,35 +1,34 @@
{
"name": "react-image-timeline",
"version": "3.2.13",
"name": "react-img-timeline",
"version": "3.2.19",
"main": "index.js",
"types": "dist/timeline.d.ts",
"homepage": "http://aaron9000.github.io/react-image-timeline",
"dependencies": {},
"devDependencies": {
"@babel/cli": "^7.2.3",
"@babel/core": "^7.2.2",
"@babel/preset-env": "^7.3.1",
"@babel/preset-react": "^7.0.0",
"@types/react": "^16.9.11",
"@types/react-dom": "^16.9.3",
"chai": "^4.2.0",
"enzyme": "^3.8.0",
"enzyme-adapter-react-16": "^1.8.0",
"gh-pages": "^2.0.1",
"node-sass": "^4.14.1",
"ramda": "^0.26.1",
"react": "^16.7.0",
"react-dom": "^16.7.0",
"react-scripts": "3.4.0",
"sinon": "^7.2.3",
"source-map-loader": "^0.2.4",
"@babel/cli": "^7.19.3",
"@babel/core": "^7.20.2",
"@babel/preset-env": "^7.20.2",
"@babel/preset-react": "^7.18.6",
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^13.4.0",
"@types/react": "^18.0.25",
"@types/react-dom": "^18.0.8",
"enzyme": "^3.11.0",
"gh-pages": "^4.0.0",
"node-sass": "^8.0.0",
"ramda": "^0.28.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-scripts": "5.0.1",
"sinon": "^14.0.2",
"source-map-loader": "^4.0.1",
"svg-inline-loader": "^0.8.2",
"ts-loader": "^6.2.1",
"typescript": "^3.6.4",
"webpack-cli": "^3.3.11"
"ts-loader": "^9.4.1",
"typescript": "^4.8.4",
"webpack-cli": "^4.10.0"
},
"peerDependencies": {
"react": "^16.0.0"
"react": "16.x || 17.x || 18.x"
},
"scripts": {
"start": "react-scripts start",
Expand Down
6 changes: 2 additions & 4 deletions src/App.test.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import React from 'react';
import ReactDOM from 'react-dom';
import {render} from '@testing-library/react'
import App from './App';

describe('<App />', () => {
it('renders without crashing', () => {
const div = document.createElement('div');
ReactDOM.render(<App />, div);
ReactDOM.unmountComponentAtNode(div);
render(<App />);
});
});
4 changes: 2 additions & 2 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ const TimelineExample = React.memo(
imageBody: CustomImageBody,
textBody: CustomTextBody,
footer: CustomFooter,
} as TimelineCustomComponents)
} as unknown)
: null;
return (
<div>
Expand Down Expand Up @@ -120,7 +120,7 @@ const TimelineExample = React.memo(
</div>
</div>
<hr />
<Timeline events={events} customComponents={customComponents} reverseOrder={reverseOrder} denseLayout={denseLayout} />
<Timeline events={events} customComponents={customComponents as TimelineCustomComponents} reverseOrder={reverseOrder} denseLayout={denseLayout} />
</div>
);
}
Expand Down
2 changes: 1 addition & 1 deletion src/data.js
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ export function getSampleData(imageType) {
const cities = getCitiesWithImages(imageType);
const mapWithIndex = R.addIndex(R.map);
return mapWithIndex((location, index) => {
return R.merge(
return R.mergeRight(
{
date: addDays(new Date('2013-12-08'), index * 8),
text: randomText(),
Expand Down
189 changes: 53 additions & 136 deletions src/lib/timeline.test.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import React from 'react';
import * as R from 'ramda';
import sinon from 'sinon';
import { expect } from 'chai';
import { shallow, mount, render } from 'enzyme';
import { render, screen, fireEvent } from '@testing-library/react';
import Timeline from './timeline';

const SHUFFLED_EVENTS = [
Expand Down Expand Up @@ -41,8 +40,6 @@ const SINGLE_INVALID_EVENT = [

const MIXED_DATES = SINGLE_INVALID_EVENT.concat(SHUFFLED_EVENTS);

const EMPTY_DIV = <div />;

const CustomHeader = props => {
return <div>*CustomHeader*</div>;
};
Expand Down Expand Up @@ -70,164 +67,97 @@ const CustomBottomLabel = props => {
describe('<Timeline />', () => {

describe('State', () => {
it("receives 'extras' in 'events' prop", () => {
const wrapper = mount(<Timeline events={SHUFFLED_EVENTS} />);
const { extras } = R.head(wrapper.props().events);
expect(extras.foo).to.equal('bar');
});

it('special cases 0 events', () => {
expect(shallow(<Timeline events={[]} />).contains(EMPTY_DIV)).to.equal(true);
render(<Timeline events={[]} />);
expect(screen.queryByText(/./)).toBeNull();
});

it('filters events with invalid dates', () => {
expect(shallow(<Timeline events={SINGLE_INVALID_EVENT} />).contains(EMPTY_DIV)).to.equal(true);
render(<Timeline events={SINGLE_INVALID_EVENT} />);
expect(screen.queryByText(/./)).toBeNull();
});

it('only filters invalid dates', () => {
expect(shallow(<Timeline events={MIXED_DATES} />).contains(EMPTY_DIV)).to.equal(false);
render(<Timeline events={MIXED_DATES} />);
expect(screen.queryAllByRole('heading')).toHaveLength(3);
});
});

describe('Labels', () => {
it('renders labels on the ends of the timeline', () => {
const wrapper = shallow(<Timeline events={SHUFFLED_EVENTS} />);
render(<Timeline events={SHUFFLED_EVENTS} />);
const listItems = screen.getAllByRole('listitem');
expect(
wrapper
.find('li')
.first()
.html()
).to.equal('<li class="rt-label-container"><div class="rt-label">2000</div></li>');
listItems[0]
).toContainHTML('<li class="rt-label-container"><div class="rt-label">2000</div></li>');
expect(
wrapper
.find('li')
.last()
.html()
).to.equal('<li class="rt-label-container"><div class="rt-label">2010</div></li>');
listItems[listItems.length - 1]
).toContainHTML('<li class="rt-label-container"><div class="rt-label">2010</div></li>');
});

it('renders reversed labels', () => {
const wrapper = shallow(<Timeline events={SHUFFLED_EVENTS} reverseOrder={true} />);
render(<Timeline events={SHUFFLED_EVENTS} reverseOrder={true} />);
const listItems = screen.getAllByRole('listitem');
expect(
wrapper
.find('li')
.first()
.html()
).to.equal('<li class="rt-label-container"><div class="rt-label">2010</div></li>');
listItems[0]
).toContainHTML('<li class="rt-label-container"><div class="rt-label">2010</div></li>');
expect(
wrapper
.find('li')
.last()
.html()
).to.equal('<li class="rt-label-container"><div class="rt-label">2000</div></li>');
listItems[listItems.length - 1]
).toContainHTML('<li class="rt-label-container"><div class="rt-label">2000</div></li>');
});
});

describe('Layout', () => {
it('renders dense layout with no minum height', () => {
const wrapper = shallow(<Timeline events={SHUFFLED_EVENTS} denseLayout={true}/>);
it('renders dense layout with no minimum height', () => {
render(<Timeline events={SHUFFLED_EVENTS} denseLayout={true}/>);
expect(
wrapper
.find('.rt-event')
.get(0)
.props
.style
).to.deep.equal({ minHeight: 'auto' });
screen
.getAllByRole('listitem')[1]
).toHaveStyle({ minHeight: 'auto' });
});

it('renders normal layout without a style override', () => {
const wrapper = shallow(<Timeline events={SHUFFLED_EVENTS} denseLayout={false}/>);
render(<Timeline events={SHUFFLED_EVENTS} denseLayout={false}/>);
expect(
wrapper
.find('.rt-event')
.get(0)
.props
.style
).to.deep.equal({});
screen
.getAllByRole('listitem')[1]
).not.toHaveStyle({ minHeight: 'auto' });
});
});


describe('Events', () => {
it('renders events correctly', () => {
const shallowWrapper = shallow(<Timeline events={SHUFFLED_EVENTS} />);
const deepWrapper = render(<Timeline events={SHUFFLED_EVENTS} />);
const assertClassCountDeep = (classes, count) => {
R.map(c => {
return expect(deepWrapper.find(c)).to.have.length(count);
}, classes);
};
const assertClassCountShallow = (classes, count) => {
R.map(c => {
return expect(shallowWrapper.find(c)).to.have.length(count);
}, classes);
};
assertClassCountShallow(['.rt-timeline', '.rt-timeline-container'], 1);
assertClassCountDeep(['.rt-label-container'], 2);
assertClassCountDeep(
[
'.rt-event',
'.rt-btn',
'.rt-image-container',
'.rt-text-container',
'.rt-header-container',
'.rt-footer-container',
],
R.length(SHUFFLED_EVENTS)
);
});

it('events call onClick when clicked', () => {
const onClick = sinon.spy();
const spiedEvents = R.map(event => {
return R.merge(event, { onClick });
return R.mergeRight(event, { onClick });
}, SHUFFLED_EVENTS);
const wrapper = mount(<Timeline events={spiedEvents} />);
wrapper
.find('button')
.first()
.simulate('click');
expect(onClick.calledOnce).to.equal(true);
render(<Timeline events={spiedEvents} />);
fireEvent(screen
.getAllByRole('button')[0], new MouseEvent('click', {bubbles: true, cancelable: true}))
expect(onClick.calledOnce).toBe(true);
});

it('renders events in order with unordered data', () => {
const wrapper = shallow(<Timeline events={SHUFFLED_EVENTS} />);
render(<Timeline events={SHUFFLED_EVENTS} />);
const listItems = screen.getAllByText(/(FIRST)|(LAST)/);
expect(
wrapper
.find('.rt-event')
.first()
.html()
.indexOf('FIRST')
).to.be.above(-1);
listItems[0]
).toHaveTextContent('FIRST');
expect(
wrapper
.find('.rt-event')
.last()
.html()
.indexOf('LAST')
).to.be.above(-1);
listItems[listItems.length - 1]
).toHaveTextContent('LAST');
});

it('renders events in reverse-order with unordered data', () => {
const wrapper = shallow(<Timeline events={SHUFFLED_EVENTS} reverseOrder={true} />);
render(<Timeline events={SHUFFLED_EVENTS} reverseOrder={true} />);
const listItems = screen.getAllByText(/(FIRST)|(LAST)/);
expect(
wrapper
.find('.rt-event')
.first()
.html()
.indexOf('LAST')
).to.be.above(-1);
listItems[0]
).toHaveTextContent('LAST');
expect(
wrapper
.find('.rt-event')
.last()
.html()
.indexOf('FIRST')
).to.be.above(-1);
listItems[listItems.length - 1]
).toHaveTextContent('FIRST');
});
});

describe('Custom Components', () => {

it('renders custom components', () => {
const CUSTOM_COMPONENTS = {
topLabel: CustomTopLabel,
Expand All @@ -237,28 +167,15 @@ describe('<Timeline />', () => {
textBody: CustomTextBody,
footer: CustomFooter,
};
const wrapper = render(<Timeline events={SHUFFLED_EVENTS} customComponents={CUSTOM_COMPONENTS} />);

const firstLabelHtml = wrapper
.find('.rt-label-container')
.first()
.html();
expect(firstLabelHtml.indexOf('*CustomTopLabel*')).to.be.above(-1);
render(<Timeline events={SHUFFLED_EVENTS} customComponents={CUSTOM_COMPONENTS} />);

const lastLabelHtml = wrapper
.find('.rt-label-container')
.last()
.html();
expect(lastLabelHtml.indexOf('*CustomBottomLabel*')).to.be.above(-1);
expect(screen.getByText('*CustomTopLabel*'));
expect(screen.getByText('*CustomBottomLabel*'));

const eventHtml = wrapper
.find('.rt-event')
.first()
.html();
expect(eventHtml.indexOf('*CustomHeader*')).to.be.above(-1);
expect(eventHtml.indexOf('*CustomImageBody*')).to.be.above(-1);
expect(eventHtml.indexOf('*CustomTextBody*')).to.be.above(-1);
expect(eventHtml.indexOf('*CustomFooter*')).to.be.above(-1);
expect(screen.getAllByText('*CustomHeader*')).toHaveLength(3);
expect(screen.getAllByText('*CustomImageBody*')).toHaveLength(3);
expect(screen.getAllByText('*CustomTextBody*')).toHaveLength(3);
expect(screen.getAllByText('*CustomFooter*')).toHaveLength(3);
});
});
});
2 changes: 1 addition & 1 deletion src/lib/timeline.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export interface TimelineEvent {
extras?: object | null;
}

export interface TimelineEventProps {
export interface TimelineEventProps extends React.ComponentPropsWithoutRef<"div"> {
event: TimelineEvent;
}

Expand Down
5 changes: 1 addition & 4 deletions src/setupTests.js
Original file line number Diff line number Diff line change
@@ -1,4 +1 @@
const Enzyme = require('enzyme');
const EnzymeAdapter = require('enzyme-adapter-react-16');

Enzyme.configure({ adapter: new EnzymeAdapter() });
import '@testing-library/jest-dom';
1 change: 0 additions & 1 deletion webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ module.exports = {
output: {
path: path.resolve(__dirname, "dist"),
filename: "timeline.js",
library: 'react-image-timeline',
libraryTarget: 'commonjs2'
},
mode: "production",
Expand Down
Loading