Skip to content

Commit

Permalink
feat: replace data table with UI data table (#3015)
Browse files Browse the repository at this point in the history
Implements https://dhis2.atlassian.net/browse/DHIS2-15795

Features:
* horizontal scrolling
* styling in line with our style guide
* virtualization (performance matches old implementation)
  • Loading branch information
jenniferarnesen authored Feb 12, 2024
1 parent def0e0c commit c3f60fe
Show file tree
Hide file tree
Showing 23 changed files with 1,656 additions and 699 deletions.
2 changes: 1 addition & 1 deletion cypress.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ module.exports = defineConfig({
// Enabled to reduce the risk of out-of-memory issues
experimentalMemoryManagement: true,
// Set to a low number to reduce the risk of out-of-memory issues
numTestsKeptInMemory: 5,
numTestsKeptInMemory: 4,
/* When allowing 1 retry on CI, the test suite will pass if
* it's flaky. And/but we also get to identify flaky tests on the
* Cypress Dashboard. */
Expand Down
8 changes: 8 additions & 0 deletions cypress/elements/event_layer.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Layer } from './layer.js'
export class EventLayer extends Layer {
selectProgram(program) {
cy.get('[data-test="programselect"]').click()
cy.contains(program).scrollIntoView()
cy.contains(program).click()

return this
Expand All @@ -22,4 +23,11 @@ export class EventLayer extends Layer {

return this
}

selectPeriodType(periodType) {
cy.getByDataTest('relative-period-select-content').click()
cy.contains(periodType).click()

return this
}
}
240 changes: 229 additions & 11 deletions cypress/integration/dataTable.cy.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,15 @@
import { EXTENDED_TIMEOUT } from '../support/util.js'
import { EventLayer } from '../elements/event_layer.js'
import { CURRENT_YEAR, EXTENDED_TIMEOUT } from '../support/util.js'

Cypress.on('uncaught:exception', (err) => {
if (
err.message.includes(
'ResizeObserver loop completed with undelivered notifications.'
)
) {
return false
}
})

const map = {
id: 'eDlFx0jTtV9',
Expand All @@ -8,7 +19,7 @@ const map = {
}

describe('data table', () => {
it('opens data table', () => {
it('opens data table and filters and sorts', () => {
cy.visit(`/#/${map.id}`, EXTENDED_TIMEOUT)
cy.get('canvas', EXTENDED_TIMEOUT).should('be.visible')

Expand All @@ -29,19 +40,226 @@ describe('data table', () => {

// check number of columns
cy.getByDataTest('bottom-panel')
.find('[role="columnheader"]')
.findByDataTest('dhis2-uicore-datatablecellhead')
.should('have.length', 10)

// try the filtering
// Filter by name
cy.getByDataTest('data-table-column-filter-input-Name')
.find('input')
.type('bar')

// check that the filter returned the correct number of rows
cy.getByDataTest('bottom-panel')
.findByDataTest('dhis2-uicore-tablebody')
.findByDataTest('dhis2-uicore-datatablerow')
.should('have.length', 7)

// confirm that the sort order is initially ascending by Name
cy.getByDataTest('bottom-panel')
.findByDataTest('dhis2-uicore-tablebody')
.find('tr')
.first()
.find('td')
.eq(1)
.should('contain', 'Bargbe')

cy.getByDataTest('bottom-panel')
.findByDataTest('dhis2-uicore-tablebody')
.find('tr')
.last()
.find('td')
.eq(1)
.should('contain', 'Upper Bambara')

// Sort by name
cy.get('button[title="Sort by Name"]').click()

// confirm that the rows are sorted by Name descending
cy.getByDataTest('bottom-panel')
.findByDataTest('dhis2-uicore-tablebody')
.find('tr')
.first()
.find('td')
.eq(1)
.should('contain', 'Upper Bambara')

cy.getByDataTest('bottom-panel')
.findByDataTest('dhis2-uicore-tablebody')
.find('tr')
.last()
.find('td')
.eq(1)
.should('contain', 'Bargbe')

// filter by Value (numeric)
cy.getByDataTest('data-table-column-filter-input-Value')
.find('input')
.type('>26')

// check that the (combined) filter returned the correct number of rows
cy.getByDataTest('bottom-panel')
.findByDataTest('dhis2-uicore-tablebody')
.findByDataTest('dhis2-uicore-datatablerow')
.should('have.length', 5)

// Sort by value
cy.get('button[title="Sort by Value"]').click()

// check that the rows are sorted by Value ascending
cy.getByDataTest('bottom-panel')
.findByDataTest('dhis2-uicore-tablebody')
.find('tr')
.first()
.find('td')
.eq(3)
.should('contain', '35')

cy.getByDataTest('bottom-panel')
.findByDataTest('dhis2-uicore-tablebody')
.find('tr')
.last()
.find('td')
.eq(3)
.should('contain', '76')

// click on a row
cy.getByDataTest('bottom-panel')
.findByDataTest('dhis2-uicore-tablebody')
.findByDataTest('dhis2-uicore-datatablerow')
.first()
.click()

// check that the org unit profile drawer is opened
cy.getByDataTest('org-unit-profile').should('be.visible')
})

it('opens the data table for an Event layer', () => {
cy.visit('/', EXTENDED_TIMEOUT)

const Layer = new EventLayer()

Layer.openDialog('Events')
.selectProgram('Malaria case registration')
.validateStage('Malaria case registration')
.selectTab('Period')
.selectPeriodType('Start/end dates')
.typeStartDate(`${CURRENT_YEAR - 1}-01-01`)
.typeEndDate(`${CURRENT_YEAR - 1}-01-15`)
.selectTab('Org Units')
.selectOu('Bo')
.addToMap()

Layer.validateDialogClosed(true)

Layer.validateCardTitle('Malaria case registration')

cy.getByDataTest('moremenubutton').first().click()

cy.getByDataTest('more-menu')
.find('li')
.contains('Show data table')
.not('disabled')
.click()

cy.getByDataTest('bottom-panel').should('be.visible')

// check number of columns
cy.getByDataTest('bottom-panel')
.findByDataTest('dhis2-uicore-datatablecellhead')
.should('have.length', 9)

cy.getByDataTest('bottom-panel')
.findByDataTest('dhis2-uicore-datatablecellhead')
.contains('Age in years', { matchCase: false })
.should('be.visible')

// filter by Org unit
const ouName = 'Benduma'
cy.getByDataTest('data-table-column-filter-input-Org unit')
.find('input')
.type(ouName)

// check that all the rows have Org unit Yakaji

cy.getByDataTest('bottom-panel')
.findByDataTest('dhis2-uicore-tablebody')
.find('tr')
.first()
.find('td')
.eq(1)
.should('contain', ouName)

cy.getByDataTest('bottom-panel')
.findByDataTest('dhis2-uicore-tablebody')
.find('tr')
.last()
.find('td')
.eq(1)
.should('contain', ouName)

cy.getByDataTest('bottom-panel')
.find('[role="columnheader"]')
.containsExact('Name')
.siblings('input')
.type('Kakua')
.findByDataTest('dhis2-uicore-tablebody')
.findByDataTest('dhis2-uicore-datatablerow')
.should('have.length', 5)

// filter by Gender
cy.getByDataTest('data-table-column-filter-input-Gender')
.find('input')
.type('Female')

cy.getByDataTest('bottom-panel')
.findByDataTest('dhis2-uicore-tablebody')
.findByDataTest('dhis2-uicore-datatablerow')
.should('have.length', 4)

cy.getByDataTest('data-table-column-filter-input-Gender')
.find('input')
.clear()

// check that the filter worked
cy.getByDataTest('bottom-panel')
.find('.ReactVirtualized__Table__row')
.should('have.length', 1)
.findByDataTest('dhis2-uicore-tablebody')
.findByDataTest('dhis2-uicore-datatablerow')
.should('have.length', 5)

// filter by Age in years (numeric)
cy.getByDataTest('data-table-column-filter-input-Age in years')
.find('input')
.type('<51')

// check that the filter returned the correct number of rows
cy.getByDataTest('bottom-panel')
.findByDataTest('dhis2-uicore-tablebody')
.findByDataTest('dhis2-uicore-datatablerow')
.should('have.length', 3)

// Sort by Age in years
cy.get('button[title="Sort by Age in years"]').click()

// confirm that the rows are sorted by Age in years descending
cy.getByDataTest('bottom-panel')
.findByDataTest('dhis2-uicore-tablebody')
.find('tr')
.first()
.find('td')
.eq(7)
.should('contain', '44')

cy.getByDataTest('bottom-panel')
.findByDataTest('dhis2-uicore-tablebody')
.find('tr')
.last()
.find('td')
.eq(7)
.should('contain', '6')

// click on a row
cy.getByDataTest('bottom-panel')
.findByDataTest('dhis2-uicore-tablebody')
.findByDataTest('dhis2-uicore-datatablerow')
.first()
.click()

// check that the org unit profile drawer is NOT opened
cy.getByDataTest('org-unit-profile').should('not.exist')
})
})
2 changes: 1 addition & 1 deletion cypress/support/commands.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import '@dhis2/cypress-commands'
import 'cypress-wait-until'

Cypress.Commands.add('getByDataTest', (selector, ...args) =>
cy.get(`[data-test=${selector}]`, ...args)
cy.get(`[data-test="${selector}"]`, ...args)
)
Cypress.Commands.add(
'findByDataTest',
Expand Down
46 changes: 32 additions & 14 deletions i18n/en.pot
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ msgstr ""
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
"POT-Creation-Date: 2024-01-11T09:20:59.829Z\n"
"PO-Revision-Date: 2024-01-11T09:20:59.829Z\n"
"POT-Creation-Date: 2024-02-12T09:30:18.362Z\n"
"PO-Revision-Date: 2024-02-12T09:30:18.362Z\n"

msgid "Untitled map, {{date}}"
msgstr "Untitled map, {{date}}"
Expand Down Expand Up @@ -131,23 +131,23 @@ msgstr "Date"
msgid "Data set"
msgstr "Data set"

msgid "Index"
msgstr "Index"
msgid "No results found"
msgstr "No results found"

msgid "Org unit"
msgstr "Org unit"
msgid "Sort by {{column}}"
msgstr "Sort by {{column}}"

msgid "Id"
msgstr "Id"
msgid "Something went wrong"
msgstr "Something went wrong"

msgid "Event time"
msgstr "Event time"
msgid "Search"
msgstr "Search"

msgid "Legend"
msgstr "Legend"
msgid "Index"
msgstr "Index"

msgid "Range"
msgstr "Range"
msgid "Id"
msgstr "Id"

msgid "Level"
msgstr "Level"
Expand All @@ -158,9 +158,27 @@ msgstr "Parent"
msgid "Type"
msgstr "Type"

msgid "Legend"
msgstr "Legend"

msgid "Range"
msgstr "Range"

msgid "Org unit"
msgstr "Org unit"

msgid "Event time"
msgstr "Event time"

msgid "Data table is not supported when events are grouped on the server."
msgstr "Data table is not supported when events are grouped on the server."

msgid "No valid data was found for the current layer configuration."
msgstr "No valid data was found for the current layer configuration."

msgid "Data table is not supported for this layer type."
msgstr "Data table is not supported for this layer type."

msgid "Items"
msgstr "Items"

Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
"@krakenjs/post-robot": "^11.0.0",
"@reportportal/agent-js-cypress": "git+https://github.com/dhis2/agent-js-cypress.git#develop",
"@reportportal/agent-js-jest": "^5.0.7",
"@testing-library/react-hooks": "^8.0.1",
"abortcontroller-polyfill": "^1.7.5",
"array-move": "^4.0.0",
"classnames": "^2.3.2",
Expand All @@ -75,6 +76,7 @@
"react-redux": "^8.1.2",
"react-sortable-hoc": "^1.11.0",
"react-virtualized": "^9.22.5",
"react-virtuoso": "^4.6.2",
"redux": "^4.2.1",
"redux-logger": "^3.0.6",
"redux-thunk": "^2.4.2",
Expand Down
Loading

0 comments on commit c3f60fe

Please sign in to comment.