Skip to content
This repository has been archived by the owner on Sep 4, 2020. It is now read-only.

Commit

Permalink
Merge pull request #1 from ebi-gene-expression-group/feature/16241679…
Browse files Browse the repository at this point in the history
…2-create-new-experiment-table

Feature/162416792 create new experiment table
  • Loading branch information
lingyun1010 committed May 8, 2019
2 parents 6ce6b7b + 6625f22 commit cb4b0c3
Show file tree
Hide file tree
Showing 19 changed files with 3,261 additions and 2,010 deletions.
90 changes: 20 additions & 70 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,73 +1,23 @@
# Template for Gene Expression Atlas and Single Cell Expression Atlas NPM packages

## Instructions

***Be sure to be running npm@4.0.0 or later. At least Node.js 8 LTS is strongly recommended.***

### Clone this repository
```
git clone https://github.com/gxa/atlas-package my-package
cd my-package
rm -rf .git
git init
git remote add origin https://github.com/gxa/my-package.git
```
Remember to create the new repository. The recommendation is to prefix the package name with “atlas-”.

### Fill in package metadata
Fill in the fields `name`, `description` and `repository`. As a general rule the packages are prefixed with
“expression-atlas-” or “sc-atlas-”. Finally, replace or remove `README.md`.

## Scripts

### `prepack`
Runs the `build` script before `npm publish`. Only the `lib` directory is packaged, so make sure everything (including
assests such as CSS or images are there).

### `postversion`, `postpublish`
After bumping the version with e.g. `npm version minor`, the package is automatically published and pushed, with all
tags, so new versions can be published in a single step.

### `test`
`npm test` runs all phases of the test lifecycle (i.e. `pretest`, `test` and `posttest`); in case you’ve added support
for Coveralls you won’t likely want to run the `posttest` phase. If that’s the case just do `npx jest`.

## Testing
Basic test boilerplate is included with [Jest](https://facebook.github.io/jest/) and
[Enzyme](http://airbnb.io/enzyme/). Jest is a test runner, an assertion library and a snapshot tester, whereas Enzyme
allows DOM testing. See the examples included in `__test__` to get an idea.

### Continuous integration
If you want CI and nice passing/failing badges, enable the repository in [Travis CI](https://travis-ci.org/). Now, with each push, Travis CI will run your tests and generate a report. You can display a test status badge going to
Travis CI, clicking on the badge and pasting the Markdown embed snippet on your `README.md`.

Enabling code coverage is very similar. You need to enable your repository in [Coveralls](https://coveralls.io/).
Every time that Travis is run, it will generate coverage information and send it to Coveralls for a coverage report.
If you go to Coveralls, you can also get a snippet to embed the coverage report shield on your readme file.

## What’s included?
- [React 16 and PropTypes](https://facebook.github.io/react/)
- [URI.js](https://medialize.github.io/URI.js/) for URL manipulation (the rich version of `query-string`)
- [Babel](https://babeljs.io/) with presets `env` and `react` (see `.babelrc`)
- [Webpack 4 with Webpack-CLI and Webpack-Dev-Server](https://webpack.js.org/)
- [Jest](https://facebook.github.io/jest/) and [Enzyme](http://airbnb.io/enzyme/) for testing

## Polyfills
No polyfills are included by default, but you might want one or both of these:
- [Fetch polyfill](https://github.com/github/fetch)
- [Babel polyfill](https://babeljs.io/docs/usage/polyfill/)

### NPM
```
npm install --save-dev whatwg-fetch @babel/polyfill
```

Tweak your `webpack.config.js` to include them in your entry points:
```
entry: {
myComponent: [`@babel/polyfill`, `whatwg-fetch`, `./html/render.js`]
...
}
# Atlas experiment table
We implement a sortable table header and check box table cell for downloading atlas experiments' files. [Evergreen Table](https://evergreen.segment.com/) component is used in this repository.

## Table header/content props structure

Table information is passed by an array of objects, named as `tableHeader`, including mandatory entries `type`, `title`, `width` and `dataParam`.
If the table cell links to another page, please indicate `link`, `resource`, `endpoint`, which will be transformed as a href to `host/resource/data[link]/endpoint`

***For example:***
```
[
{type: `plain`, title: `index`, width: 60, dataParam: null, link: null}
{type: `sort`, title: `Loaded date`, width: 140, dataParam: `lastUpdate`, link: null},
{type: `search`, title: `species`, width: 200, dataParam: `species`, link: null},
{type: `search`, title: `experiment description`, width: 360, dataParam: `experimentDescription`,
link: `experimentAccession`, resource: `experiments`, endpoint: `Results`},
{type: `search`, title: `experiment factors`, width: 260, dataParam: `experimentalFactors`, link: null},
{type: `sort`, title: `Number of assays`, width: 160, dataParam: `numberOfAssays`,
link: `experimentAccession`, resource: `experiments`, endpoint: `Experiment Design`}
]
```

## Run it on your browser
Expand Down
107 changes: 107 additions & 0 deletions __test__/ExperimentTable.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import React from 'react'
import Enzyme from 'enzyme'
import {shallow, mount} from 'enzyme'
import Adapter from 'enzyme-adapter-react-16'
import {getRandomInt, TableCellDiv, data, tableHeader} from './TestUtils'
import ExperimentTable from '../src/ExperimentTable'
import TableFooter from '../src/TableFooter'
import TableContent from '../src/TableContent'
import TableSearchHeader from '../src/TableSearchHeader'
import { Table } from 'evergreen-ui'
import _ from "lodash"

Enzyme.configure({ adapter: new Adapter() })

describe(`ExperimentTable`, () => {
const props = {
aaData: data,
tableHeader: tableHeader,
host: `fool`,
resource: `bool`,
enableDownload: true,
enableIndex: true,
TableCellDiv: TableCellDiv
}

test(`should render three search general boxes and a table with head and body and two bottom info boxes`, () => {
const wrapper = shallow(<ExperimentTable {...props}/>)
expect(wrapper.find(TableSearchHeader)).toHaveLength(1)
expect(wrapper.find(TableContent)).toHaveLength(1)
expect(wrapper.find(TableFooter)).toHaveLength(1)
})


test(`should sort table content and change header text icon`, () => {
const randomColumnIndex = getRandomInt(1, tableHeader.length)
props.tableHeader[randomColumnIndex].type=`sort`
const wrapper = mount(<ExperimentTable {...props}/>)

expect(wrapper.find(`.icon.icon-common.icon-sort-up`)).toHaveLength(1)
expect(wrapper.find(`.icon.icon-common.icon-sort-down`)).toHaveLength(0)

const sortedHeader = wrapper.find(`.header${randomColumnIndex}`).at(0)
sortedHeader.simulate('click')
wrapper.update()
expect(wrapper.find(`.icon.icon-common.icon-sort-up`)).toHaveLength(0)
sortedHeader.simulate('click')
wrapper.update()
expect(wrapper.find(`.icon.icon-common.icon-sort-up`)).toHaveLength(1)
})

test(`should filter based on kingdom selection`, () => {
const event = {target: {name: `pollName`, value: `animals`}}
const wrapper = mount(<ExperimentTable {...props}/>)
const kingdomSearch = wrapper.find(`select`).first().at(0)
kingdomSearch.simulate(`change`, event)

expect(wrapper.state(`selectedKingdom`)).toEqual(`animals`)
expect(wrapper.find(Table.Row).length).toBeLessThanOrEqual(data.length)
})

test(`should filter based on table header search`, () => {
const randomValue = `si`
const randomColumn = getRandomInt(1, tableHeader.length)
props.tableHeader[randomColumn].type=`search`

const wrapper = mount(<ExperimentTable {...props}/>)
expect(wrapper.find(`.searchheader${randomColumn}`).exists()).toBe(true)
wrapper.setState({searchQuery: randomValue})
wrapper.update()
expect(wrapper.find(Table.Row).length).toBeLessThanOrEqual(data.length)
})

test(`should change page by clicking buttons`, () => {
const wrapper = mount(<ExperimentTable {...props}/>)
const currentPage = wrapper.state().currentPage
wrapper.setState({entriesPerPage: 1, currentPage: 1})
wrapper.update()

const nextButton = wrapper.find('.pagination li').last()
nextButton.children().simulate(`click`)
wrapper.update()
expect(wrapper.state().currentPage).toEqual(currentPage + 1)

const prevButton = wrapper.find('.pagination li').first()
prevButton.children().simulate(`click`)
expect(wrapper.state().currentPage).toEqual(currentPage)

const currentNumberButton = wrapper.find(`.current`)
expect(currentNumberButton).toHaveLength(1)
})

test(`should save experiment accession by check download box`, () => {
const randomRow = getRandomInt(0, data.length)

const wrapper = mount(<ExperimentTable {...props} enableDownload={true}/>)
const propKey = tableHeader[wrapper.state(`orderedColumnIndex`)].dataParam
const sortedElements = _.sortBy(data, propKey)

expect(wrapper.state(`checkedRows`)).toEqual([])
const checkbox = wrapper.find(`.checkbox`).at(randomRow)
checkbox.simulate(`change`)
expect(wrapper.state(`checkedRows`)).toEqual([sortedElements[randomRow].experimentAccession])
checkbox.simulate(`change`)
expect(wrapper.state(`checkedRows`)).toEqual([])
})

})
32 changes: 0 additions & 32 deletions __test__/MyComponent.test.js

This file was deleted.

56 changes: 56 additions & 0 deletions __test__/TableContent.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import React from 'react'
import Enzyme from 'enzyme'
import {shallow} from 'enzyme'
import Adapter from 'enzyme-adapter-react-16'
import { data } from './TestUtils'

import TableContent from '../src/TableContent'
import { Table } from 'evergreen-ui'

Enzyme.configure({ adapter: new Adapter() })

describe(`TableContent`, () => {
const props = {
enableIndex: true,
tableHeader: [{
type: `search`,
title: `title1`,
width: 12,
dataParam: `hello`
},
{
type: `search`,
title: `title2`,
width: 3,
dataParam: `hi`
}],
searchedColumnIndex: 2,
searchQuery: `search`,
orderedColumnIndex: 1,
ascendingOrder: true,
enableDownload: true,
checkedRows: [1, 2],
currentPageData: data,
host: `boo`,
entriesPerPage: 2,
currentPage: 1,
tableHeaderOnClick: () => {},
tableHeaderOnChange: () => {},
downloadOnChange: () => {}
}

test(`should render a previous button, a next button and information text`, () => {
const wrapper = shallow(<TableContent {...props}/>)
expect(wrapper.find(Table)).toHaveLength(1)
expect(wrapper.find(Table.Head)).toHaveLength(1)
expect(wrapper.find(Table.Body)).toHaveLength(1)
})

test(`should show/hide download based on props`, () => {
const wrapper = shallow(<TableContent {...props} enableDownload={true}/>)
expect(wrapper.find(`.downloadHeader`)).toHaveLength(1)

const wrapperNoDownload= shallow(<TableContent {...props} enableDownload={false}/>)
expect(wrapperNoDownload.find(`.downloadHeader`)).toHaveLength(0)
})
})
26 changes: 26 additions & 0 deletions __test__/TableFooter.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import React from 'react'
import Enzyme from 'enzyme'
import {shallow} from 'enzyme'
import Adapter from 'enzyme-adapter-react-16'
import { data } from './TestUtils'
import TableFooter from '../src/TableFooter'

Enzyme.configure({ adapter: new Adapter() })

describe(`TableFooter`, () => {
const props = {
dataArrayLength: Math.random() * 10,
entriesPerPage: 1,
selectedNumber: 2,
dataLength: data.length,
currentPage: 1,
onChange: () => {}
}

test(`should render a previous button, a next button and information text`, () => {
const wrapper = shallow(<TableFooter {...props}/>)
expect(wrapper.find(`li`).first().key()).toBe(`previous`)
expect(wrapper.find(`li`).last().key()).toBe(`next`)
})

})
27 changes: 27 additions & 0 deletions __test__/TableSearchHeader.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import React from 'react'
import Enzyme from 'enzyme'
import {shallow} from 'enzyme'
import Adapter from 'enzyme-adapter-react-16'
import { data } from './TestUtils'
import TableSearchHeader from '../src/TableSearchHeader'

Enzyme.configure({ adapter: new Adapter() })

describe(`TableSearchHeader`, () => {
const props = {
kingdomOptions: [`hello`, `bonjour`],
entriesPerPageOptions: [1, 4, 5, 100],
aaData: data,
searchAllOnChange: () => {},
numberOfEntriesPerPageOnChange: () => {},
kingdomOnChange: () => {},
totalNumberOfRows: 2
}

test(`should render two dropdown menues and a search box`, () => {
const wrapper = shallow(<TableSearchHeader {...props}/>)
expect(wrapper.find(`select`)).toHaveLength(2)
expect(wrapper.find(`input`)).toHaveLength(1)
})

})
Loading

0 comments on commit cb4b0c3

Please sign in to comment.