UNPKG

@ministryofjustice/hmpps-digital-prison-reporting-frontend

Version:

The Digital Prison Reporting Frontend contains templates and code to help display data effectively in UI applications.

488 lines (476 loc) 13 kB
import Dict = NodeJS.Dict import { components } from '../../types/api' import SectionedDataTableBuilder from './SectionedDataTableBuilder' const data: Array<Dict<string>> = [ { sectionOne: 'A', sectionTwo: '01/02/03', oranges: '5', lemons: 'Yes', }, { sectionOne: 'A', sectionTwo: '01/02/03', oranges: '6', lemons: 'No', }, { sectionOne: 'A', sectionTwo: '02/01/03', oranges: '7', lemons: 'Yeah', }, { sectionOne: 'B', sectionTwo: '02/01/03', oranges: '8', lemons: 'Nah', }, ] const fields: Array<components['schemas']['FieldDefinition']> = [ { name: 'sectionOne', display: 'Section One', sortable: true, defaultsort: false, type: 'string', mandatory: false, visible: false, calculated: false, }, { name: 'sectionTwo', display: 'Section Two', sortable: true, defaultsort: false, type: 'string', mandatory: false, visible: false, calculated: false, }, { name: 'oranges', display: 'Oranges!', sortable: true, defaultsort: true, type: 'long', mandatory: false, visible: true, calculated: false, }, { name: 'lemons', display: 'Lemons?!', sortable: true, defaultsort: false, type: 'string', mandatory: false, visible: true, calculated: false, }, ] const specification: components['schemas']['Specification'] = { fields, template: 'list-section', sections: ['sectionOne', 'sectionTwo'], } const headerResultRow = [ { classes: 'govuk-table__header', text: 'Oranges!', }, { classes: 'govuk-table__header', text: 'Lemons?!', }, ] const resultRows = [ [ { classes: '', fieldName: 'oranges', format: 'numeric', text: '5', }, { classes: '', fieldName: 'lemons', format: 'string', text: 'Yes', }, ], [ { classes: '', fieldName: 'oranges', format: 'numeric', text: '6', }, { classes: '', fieldName: 'lemons', format: 'string', text: 'No', }, ], [ { classes: '', fieldName: 'oranges', format: 'numeric', text: '7', }, { classes: '', fieldName: 'lemons', format: 'string', text: 'Yeah', }, ], [ { classes: '', fieldName: 'oranges', format: 'numeric', text: '8', }, { classes: '', fieldName: 'lemons', format: 'string', text: 'Nah', }, ], ] const sectionHeaders = [ [ [ { classes: 'dpr-section-header-spacer', colspan: 2, text: '', }, ], [ { classes: 'dpr-section-header', colspan: 2, html: '<h2 class="govuk-heading-m">Section One: A, Section Two: 01/02/03 <span class=\'govuk-caption-m\'>2 results</span></h2>', }, ], [ { classes: 'dpr-section-header-spacer-bottom', colspan: 2, text: '', }, ], ], [ [ { classes: 'dpr-section-header', colspan: 2, html: '<h2 class="govuk-heading-m">Section One: A, Section Two: 02/01/03 <span class=\'govuk-caption-m\'>1 result</span></h2>', }, ], [ { classes: 'dpr-section-header-spacer-bottom', colspan: 2, text: '', }, ], ], [ [ { classes: 'dpr-section-header-spacer', colspan: 2, text: '', }, ], [ { classes: 'dpr-section-header', colspan: 2, html: '<h2 class="govuk-heading-m">Section One: B, Section Two: 02/01/03 <span class=\'govuk-caption-m\'>1 result</span></h2>', }, ], [ { classes: 'dpr-section-header-spacer-bottom', colspan: 2, text: '', }, ], ], ] describe('SectionedDataTableBuilder', () => { it('Sections added correctly', () => { const mapped = new SectionedDataTableBuilder(specification) .withNoHeaderOptions(['oranges', 'lemons']) .buildTable(data) expect(mapped.rows).toEqual([ ...sectionHeaders[1], headerResultRow, resultRows[2], ...sectionHeaders[0], headerResultRow, resultRows[0], resultRows[1], ...sectionHeaders[2], headerResultRow, resultRows[3], ]) expect(mapped.head).toBeNull() expect(mapped.colCount).toEqual(2) expect(mapped.rowCount).toEqual(4) }) it('Section table summaries added correctly', () => { const mapped = new SectionedDataTableBuilder(specification) .withNoHeaderOptions(['oranges', 'lemons']) .withSummaries({ 'table-header': [ { id: 'table-header', template: 'table-header', fields: [], data: [ { sectionOne: 'A', sectionTwo: '01/02/03', oranges: 'Fruit', lemons: 'Lots', }, { sectionOne: 'A', sectionTwo: '02/01/03', oranges: 'Fruit', lemons: 'Not so much', }, ], }, ], 'table-footer': [ { id: 'table-footer', template: 'table-footer', fields: [], data: [ { sectionOne: 'A', sectionTwo: '02/01/03', oranges: 'Strawberry', lemons: 'Lime', }, { sectionOne: 'B', sectionTwo: '02/01/03', oranges: 'Apples', lemons: 'Oh no', }, ], }, ], }) .buildTable(data) expect(mapped.rows).toEqual([ ...sectionHeaders[1], headerResultRow, [ { classes: 'dpr-report-summary-cell dpr-report-summary-cell-table-header', fieldName: 'oranges', format: 'numeric', text: 'Fruit', }, { classes: 'dpr-report-summary-cell dpr-report-summary-cell-table-header', fieldName: 'lemons', format: 'string', text: 'Not so much', }, ], resultRows[2], [ { classes: 'dpr-report-summary-cell dpr-report-summary-cell-table-footer', fieldName: 'oranges', format: 'numeric', text: 'Strawberry', }, { classes: 'dpr-report-summary-cell dpr-report-summary-cell-table-footer', fieldName: 'lemons', format: 'string', text: 'Lime', }, ], ...sectionHeaders[0], headerResultRow, [ { classes: 'dpr-report-summary-cell dpr-report-summary-cell-table-header', fieldName: 'oranges', format: 'numeric', text: 'Fruit', }, { classes: 'dpr-report-summary-cell dpr-report-summary-cell-table-header', fieldName: 'lemons', format: 'string', text: 'Lots', }, ], resultRows[0], resultRows[1], ...sectionHeaders[2], headerResultRow, resultRows[3], [ { classes: 'dpr-report-summary-cell dpr-report-summary-cell-table-footer', fieldName: 'oranges', format: 'numeric', text: 'Apples', }, { classes: 'dpr-report-summary-cell dpr-report-summary-cell-table-footer', fieldName: 'lemons', format: 'string', text: 'Oh no', }, ], ]) expect(mapped.head).toBeNull() expect(mapped.colCount).toEqual(2) expect(mapped.rowCount).toEqual(4) }) it('Section summaries added correctly', () => { const mapped = new SectionedDataTableBuilder(specification) .withNoHeaderOptions(['oranges', 'lemons']) .withSummaries({ 'section-header': [ { id: 'section-header', template: 'section-header', fields: [ { name: 'squishy', display: 'Squishy?', type: 'boolean', }, ], data: [ { sectionOne: 'A', sectionTwo: '01/02/03', squishy: 'Yes', }, { sectionOne: 'A', sectionTwo: '02/01/03', squishy: 'No', }, ], }, ], 'section-footer': [ { id: 'section-footer', template: 'section-footer', fields: [ { name: 'preference', display: 'Preference', type: 'string', }, { name: 'eaten', display: 'Eaten', type: 'long', }, ], data: [ { sectionOne: 'A', sectionTwo: '02/01/03', preference: 'Oranges', eaten: '2005', }, { sectionOne: 'B', sectionTwo: '02/01/03', preference: 'NO', eaten: '0', }, { sectionOne: 'B', sectionTwo: '02/01/03', preference: 'No, really', eaten: '0', }, ], }, ], }) .buildTable(data) expect(mapped.rows).toEqual([ ...sectionHeaders[1], [ { classes: 'dpr-summary-cell', colspan: 2, html: "<div class='dpr-summary-container-group dpr-summary-container-group-section-header'><div class='dpr-summary-container'><table class='govuk-table'><thead class='govuk-table__head'><th scope='col' class='govuk-table__header'>Squishy?</th></thead><tbody class='govuk-table__body'><tr class='govuk-table__row'><td class='govuk-table__cell govuk-table__cell--string '>No</td></tr></tbody></table></div></div>", }, ], headerResultRow, resultRows[2], [ { classes: 'dpr-summary-cell', colspan: 2, html: "<div class='dpr-summary-container-group dpr-summary-container-group-section-footer'><div class='dpr-summary-container'><table class='govuk-table'><thead class='govuk-table__head'><th scope='col' class='govuk-table__header'>Preference</th><th scope='col' class='govuk-table__header'>Eaten</th></thead><tbody class='govuk-table__body'><tr class='govuk-table__row'><td class='govuk-table__cell govuk-table__cell--string '>Oranges</td><td class='govuk-table__cell govuk-table__cell--numeric '>2005</td></tr></tbody></table></div></div>", }, ], ...sectionHeaders[0], [ { classes: 'dpr-summary-cell', colspan: 2, html: "<div class='dpr-summary-container-group dpr-summary-container-group-section-header'><div class='dpr-summary-container'><table class='govuk-table'><thead class='govuk-table__head'><th scope='col' class='govuk-table__header'>Squishy?</th></thead><tbody class='govuk-table__body'><tr class='govuk-table__row'><td class='govuk-table__cell govuk-table__cell--string '>Yes</td></tr></tbody></table></div></div>", }, ], headerResultRow, resultRows[0], resultRows[1], ...sectionHeaders[2], headerResultRow, resultRows[3], [ { classes: 'dpr-summary-cell', colspan: 2, html: "<div class='dpr-summary-container-group dpr-summary-container-group-section-footer'><div class='dpr-summary-container'><table class='govuk-table'><thead class='govuk-table__head'><th scope='col' class='govuk-table__header'>Preference</th><th scope='col' class='govuk-table__header'>Eaten</th></thead><tbody class='govuk-table__body'><tr class='govuk-table__row'><td class='govuk-table__cell govuk-table__cell--string '>No, really</td><td class='govuk-table__cell govuk-table__cell--numeric '>0</td></tr><tr class='govuk-table__row'><td class='govuk-table__cell govuk-table__cell--string '>NO</td><td class='govuk-table__cell govuk-table__cell--numeric '>0</td></tr></tbody></table></div></div>", }, ], ]) expect(mapped.head).toBeNull() expect(mapped.colCount).toEqual(2) expect(mapped.rowCount).toEqual(4) }) it('Large volumes of sections added correctly', () => { let bigData: Dict<string>[] = [] for (let d = 0; d < 10000; d += 1) { bigData = bigData.concat(data) } const mapped = new SectionedDataTableBuilder(specification) .withNoHeaderOptions(['oranges', 'lemons']) .buildTable(bigData) expect(mapped.head).toBeNull() expect(mapped.colCount).toEqual(2) expect(mapped.rowCount).toEqual(40000) expect(mapped.rows.length).toEqual(40011) }) })