@hrforte/react-pivottable 2.2.2 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/PivotDataWorker.js +219 -13
- package/dist/PivotDataWorker.js.map +1 -1
- package/dist/PivotTable.js +2 -1
- package/dist/PivotTable.js.map +1 -1
- package/dist/PivotTableUI.js +39 -66
- package/dist/PivotTableUI.js.map +1 -1
- package/dist/TableRenderers.js +568 -106
- package/dist/TableRenderers.js.map +1 -1
- package/dist/Utilities.js +104 -179
- package/dist/Utilities.js.map +1 -1
- package/dist/__tests__/PivotDataWorker-test.js +437 -7
- package/dist/__tests__/PivotDataWorker-test.js.map +1 -1
- package/dist/__tests__/PivotTableUI-processing-test.js +41 -2
- package/dist/__tests__/PivotTableUI-processing-test.js.map +1 -1
- package/dist/__tests__/TableRenderers-showNumericalOrder-test.js +449 -0
- package/dist/__tests__/TableRenderers-showNumericalOrder-test.js.map +1 -1
- package/dist/__tests__/pivotCompute-test.js +137 -0
- package/dist/__tests__/pivotCompute-test.js.map +1 -1
- package/dist/pivot-worker.js +509 -201
- package/dist/pivotCompute.js +237 -12
- package/dist/pivotCompute.js.map +1 -1
- package/dist/pivotWorker.js +165 -9
- package/dist/pivotWorker.js.map +1 -1
- package/dist/pivottable.css +274 -266
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/__tests__/PivotTableUI-processing-test.js"],"names":["global","IS_REACT_ACT_ENVIRONMENT","records","name","gender","colour","trials","baseProps","data","rows","cols","aggregatorName","vals","rendererName","rerenderPivot","root","props","render","React","createElement","PivotTableUI","describe","containers","beforeEach","afterEach","forEach","container","unmount","node","remove","mount","document","body","appendChild","entry","push","it","expect","querySelector","toBeNull","not","Object","assign","showProcessing","overlay","textContent","toBe","PivotLoadingOverlay","wait","Promise","setTimeout","resolve","ms","actAsync","reject","callback","then","workerInstances","FakeWorker","url","posted","onmessage","message","previousWorker","Worker","workerThreshold","restore","WORKER_DEBOUNCE_MS","worker","toBeDefined","computeMsg","find","m","type","result","id","catch","error"],"mappings":"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","file":"PivotTableUI-processing-test.js","sourcesContent":["import React, {act} from 'react';\nimport {createRoot} from 'react-dom/client';\nimport PivotTableUI, {PivotLoadingOverlay} from '../PivotTableUI';\nimport {\n computePivotState,\n createWorkerConfig,\n materializeData,\n WORKER_DEBOUNCE_MS,\n} from '../pivotCompute';\n/* eslint-disable no-magic-numbers */\n\n// React 19 needs to be told that this environment supports `act`.\nglobal.IS_REACT_ACT_ENVIRONMENT = true;\n\n// `showProcessing` is a debugging/testing hook that forces the loading\n// overlay on top of the rendered table without running a real worker\n// computation, so the overlay can be inspected while consuming the package.\nconst records = [\n {name: 'Nick', gender: 'male', colour: 'blue', trials: 103},\n {name: 'Jane', gender: 'female', colour: 'red', trials: 95},\n {name: 'John', gender: 'male', colour: 'blue', trials: 112},\n {name: 'Carol', gender: 'female', colour: 'yellow', trials: 102},\n];\n\nconst baseProps = {\n data: records,\n rows: ['name'],\n cols: [],\n aggregatorName: 'Count',\n vals: [],\n rendererName: 'Table',\n};\n\nfunction rerenderPivot(root, props) {\n act(() => {\n root.render(React.createElement(PivotTableUI, props));\n });\n}\n\ndescribe(' PivotTableUI showProcessing', function() {\n let containers;\n\n beforeEach(function() {\n containers = [];\n });\n\n afterEach(function() {\n containers.forEach(container => {\n act(() => {\n container.root.unmount();\n });\n container.node.remove();\n });\n });\n\n const mount = props => {\n const node = document.createElement('div');\n document.body.appendChild(node);\n const root = createRoot(node);\n act(() => {\n root.render(React.createElement(PivotTableUI, props));\n });\n const entry = {node, root};\n containers.push(entry);\n return entry;\n };\n\n it('does not render the overlay by default', function() {\n const {node} = mount(baseProps);\n expect(node.querySelector('.pvtLoadingOverlay')).toBeNull();\n expect(node.querySelector('.pvtTable')).not.toBeNull();\n });\n\n it('renders the overlay on top of the table when showProcessing is true', function() {\n const {node, root} = mount(baseProps);\n // Table is rendered from the real data first (no overlay).\n expect(node.querySelector('.pvtTable')).not.toBeNull();\n expect(node.querySelector('.pvtLoadingOverlay')).toBeNull();\n\n rerenderPivot(root, Object.assign({}, baseProps, {showProcessing: true}));\n\n const overlay = node.querySelector('.pvtLoadingOverlay');\n expect(overlay).not.toBeNull();\n // The overlay is layered on top of the table: the table must survive.\n expect(node.querySelector('.pvtTable')).not.toBeNull();\n // Only a spinner and a label: progress percentages were removed, the\n // overlay simply stays until the worker posts its result event.\n expect(overlay.querySelector('.pvtLoadingSpinner')).not.toBeNull();\n expect(overlay.querySelector('.pvtLoadingText').textContent).toBe(\n 'Processing…'\n );\n expect(overlay.querySelector('.pvtLoadingBar')).toBeNull();\n expect(overlay.querySelector('.pvtLoadingPercent')).toBeNull();\n\n // Turning the flag back off removes the overlay.\n rerenderPivot(root, baseProps);\n expect(node.querySelector('.pvtLoadingOverlay')).toBeNull();\n });\n\n it('renders a spinner without any percentage markup', function() {\n const node = document.createElement('div');\n act(() => {\n createRoot(node).render(React.createElement(PivotLoadingOverlay, null));\n });\n expect(node.querySelector('.pvtLoadingOverlay')).not.toBeNull();\n expect(node.querySelector('.pvtLoadingSpinner')).not.toBeNull();\n expect(node.querySelector('.pvtLoadingBarWrap')).toBeNull();\n expect(node.querySelector('.pvtLoadingPercent')).toBeNull();\n expect(node.querySelector('.pvtLoadingText').textContent).toBe(\n 'Processing…'\n );\n });\n\n it('hides the overlay only after the worker responds and the table renders', function() {\n const wait = ms => new Promise(resolve => setTimeout(resolve, ms));\n // React's act() returns a non-standard thenable whose .then() does not\n // return a promise, so it cannot be chained directly - wrap it first.\n const actAsync = callback =>\n new Promise((resolve, reject) => act(callback).then(resolve, reject));\n const workerInstances = [];\n class FakeWorker {\n constructor(url) {\n this.url = url;\n this.posted = [];\n this.onmessage = null;\n workerInstances.push(this);\n }\n\n postMessage(message) {\n this.posted.push(message);\n }\n\n terminate() {}\n }\n\n const previousWorker = global.Worker;\n global.Worker = FakeWorker;\n\n // workerThreshold: 2 makes this small dataset worker-eligible.\n const props = Object.assign({}, baseProps, {workerThreshold: 2});\n const {node} = mount(props);\n\n const restore = () => {\n global.Worker = previousWorker;\n };\n\n // The overlay is up while the computation is pending.\n expect(node.querySelector('.pvtLoadingOverlay')).not.toBeNull();\n\n // Wait out the dispatch debounce so the request reaches the worker.\n return actAsync(() => wait(WORKER_DEBOUNCE_MS + 50))\n .then(() => {\n const worker = workerInstances[0];\n expect(worker).toBeDefined();\n const computeMsg = worker.posted.find(m => m.type === 'pivot:compute');\n expect(computeMsg).toBeDefined();\n // The worker has not answered yet: the overlay must stay up.\n expect(node.querySelector('.pvtLoadingOverlay')).not.toBeNull();\n\n // Worker finishes and posts its result event.\n const result = computePivotState(\n materializeData(records, {}),\n createWorkerConfig(props)\n );\n return actAsync(() => {\n worker.onmessage({\n data: {type: 'pivot:result', id: computeMsg.id, result},\n });\n return wait(0);\n });\n })\n .then(() => {\n // The overlay is gone only now - and the freshly computed table is\n // already on screen in the same state where the overlay disappeared.\n expect(node.querySelector('.pvtLoadingOverlay')).toBeNull();\n expect(node.querySelector('.pvtTable')).not.toBeNull();\n restore();\n })\n .catch(error => {\n restore();\n throw error;\n });\n });\n});\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/__tests__/PivotTableUI-processing-test.js"],"names":["global","IS_REACT_ACT_ENVIRONMENT","records","name","gender","colour","trials","baseProps","data","rows","cols","aggregatorName","vals","rendererName","rerenderPivot","root","props","render","React","createElement","PivotTableUI","describe","containers","beforeEach","afterEach","forEach","container","unmount","node","remove","mount","document","body","appendChild","entry","push","it","expect","querySelector","toBeNull","not","originalWorker","Worker","errorSpy","jest","spyOn","console","mockImplementation","Object","assign","Array","fill","map","_","index","warnings","mock","calls","call","join","filter","message","includes","toEqual","mockRestore","showProcessing","overlay","parentElement","classList","contains","toBe","textContent","PivotLoadingOverlay","wait","Promise","setTimeout","resolve","ms","actAsync","reject","callback","then","workerInstances","FakeWorker","url","posted","onmessage","previousWorker","workerThreshold","restore","WORKER_DEBOUNCE_MS","worker","toBeDefined","computeMsg","find","m","type","result","id","catch","error"],"mappings":";;;;AAAA;;;;AACA;;AACA;;;;AACA;;;;;;AAMA;;AAEA;AACAA,OAAOC,wBAAP,GAAkC,IAAlC;;AAEA;AACA;AACA;AACA,IAAMC,UAAU,CACd,EAACC,MAAM,MAAP,EAAeC,QAAQ,MAAvB,EAA+BC,QAAQ,MAAvC,EAA+CC,QAAQ,GAAvD,EADc,EAEd,EAACH,MAAM,MAAP,EAAeC,QAAQ,QAAvB,EAAiCC,QAAQ,KAAzC,EAAgDC,QAAQ,EAAxD,EAFc,EAGd,EAACH,MAAM,MAAP,EAAeC,QAAQ,MAAvB,EAA+BC,QAAQ,MAAvC,EAA+CC,QAAQ,GAAvD,EAHc,EAId,EAACH,MAAM,OAAP,EAAgBC,QAAQ,QAAxB,EAAkCC,QAAQ,QAA1C,EAAoDC,QAAQ,GAA5D,EAJc,CAAhB;;AAOA,IAAMC,YAAY;AAChBC,QAAMN,OADU;AAEhBO,QAAM,CAAC,MAAD,CAFU;AAGhBC,QAAM,EAHU;AAIhBC,kBAAgB,OAJA;AAKhBC,QAAM,EALU;AAMhBC,gBAAc;AANE,CAAlB;;AASA,SAASC,aAAT,CAAuBC,IAAvB,EAA6BC,KAA7B,EAAoC;AAClC,kBAAI,YAAM;AACRD,SAAKE,MAAL,CAAYC,gBAAMC,aAAN,CAAoBC,sBAApB,EAAkCJ,KAAlC,CAAZ;AACD,GAFD;AAGD;;AAEDK,SAAS,+BAAT,EAA0C,YAAW;AACnD,MAAIC,mBAAJ;;AAEAC,aAAW,YAAW;AACpBD,iBAAa,EAAb;AACD,GAFD;;AAIAE,YAAU,YAAW;AACnBF,eAAWG,OAAX,CAAmB,qBAAa;AAC9B,sBAAI,YAAM;AACRC,kBAAUX,IAAV,CAAeY,OAAf;AACD,OAFD;AAGAD,gBAAUE,IAAV,CAAeC,MAAf;AACD,KALD;AAMD,GAPD;;AASA,MAAMC,QAAQ,SAARA,KAAQ,QAAS;AACrB,QAAMF,OAAOG,SAASZ,aAAT,CAAuB,KAAvB,CAAb;AACAY,aAASC,IAAT,CAAcC,WAAd,CAA0BL,IAA1B;AACA,QAAMb,OAAO,wBAAWa,IAAX,CAAb;AACA,oBAAI,YAAM;AACRb,WAAKE,MAAL,CAAYC,gBAAMC,aAAN,CAAoBC,sBAApB,EAAkCJ,KAAlC,CAAZ;AACD,KAFD;AAGA,QAAMkB,QAAQ,EAACN,UAAD,EAAOb,UAAP,EAAd;AACAO,eAAWa,IAAX,CAAgBD,KAAhB;AACA,WAAOA,KAAP;AACD,GAVD;;AAYAE,KAAG,wCAAH,EAA6C,YAAW;AAAA,iBACvCN,MAAMvB,SAAN,CADuC;AAAA,QAC/CqB,IAD+C,UAC/CA,IAD+C;;AAEtDS,WAAOT,KAAKU,aAAL,CAAmB,oBAAnB,CAAP,EAAiDC,QAAjD;AACAF,WAAOT,KAAKU,aAAL,CAAmB,WAAnB,CAAP,EAAwCE,GAAxC,CAA4CD,QAA5C;AACD,GAJD;;AAMAH,KAAG,gEAAH,EAAqE,YAAW;AAC9E,QAAMK,iBAAiBzC,OAAO0C,MAA9B;AACA,QAAMC,WAAWC,KAAKC,KAAL,CAAWC,OAAX,EAAoB,OAApB,EAA6BC,kBAA7B,CAAgD,YAAM,CAAE,CAAxD,CAAjB;AACA/C,WAAO0C,MAAP;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA,sCACgB,CAAE;AADlB;AAAA;AAAA,oCAEc,CAAE;AAFhB;;AAAA;AAAA;AAIA,QAAI;AACFZ,YACEkB,OAAOC,MAAP,CAAc,EAAd,EAAkB1C,SAAlB,EAA6B;AAC3BC,cAAM,IAAI0C,KAAJ,CAAU,GAAV,EAAeC,IAAf,CAAoB,IAApB,EAA0BC,GAA1B,CAA8B,UAACC,CAAD,EAAIC,KAAJ;AAAA,iBAAe;AACjDnD,gCAAkBmD;AAD+B,WAAf;AAAA,SAA9B;AADqB,OAA7B,CADF;AAOA,UAAMC,WAAWZ,SAASa,IAAT,CAAcC,KAAd,CACdL,GADc,CACV;AAAA,eAAQM,KAAKC,IAAL,CAAU,GAAV,CAAR;AAAA,OADU,EAEdC,MAFc,CAEP;AAAA,eAAWC,QAAQC,QAAR,CAAiB,YAAjB,CAAX;AAAA,OAFO,CAAjB;AAGAzB,aAAOkB,QAAP,EAAiBQ,OAAjB,CAAyB,EAAzB;AACD,KAZD,SAYU;AACR/D,aAAO0C,MAAP,GAAgBD,cAAhB;AACAE,eAASqB,WAAT;AACD;AACF,GAvBD;;AAyBA5B,KAAG,qEAAH,EAA0E,YAAW;AAAA,kBAC9DN,MAAMvB,SAAN,CAD8D;AAAA,QAC5EqB,IAD4E,WAC5EA,IAD4E;AAAA,QACtEb,IADsE,WACtEA,IADsE;AAEnF;;;AACAsB,WAAOT,KAAKU,aAAL,CAAmB,WAAnB,CAAP,EAAwCE,GAAxC,CAA4CD,QAA5C;AACAF,WAAOT,KAAKU,aAAL,CAAmB,oBAAnB,CAAP,EAAiDC,QAAjD;;AAEAzB,kBAAcC,IAAd,EAAoBiC,OAAOC,MAAP,CAAc,EAAd,EAAkB1C,SAAlB,EAA6B,EAAC0D,gBAAgB,IAAjB,EAA7B,CAApB;;AAEA,QAAMC,UAAUtC,KAAKU,aAAL,CAAmB,oBAAnB,CAAhB;AACAD,WAAO6B,OAAP,EAAgB1B,GAAhB,CAAoBD,QAApB;AACAF,WAAO6B,QAAQC,aAAR,CAAsBC,SAAtB,CAAgCC,QAAhC,CAAyC,WAAzC,CAAP,EAA8DC,IAA9D,CAAmE,IAAnE;AACA;AACAjC,WAAOT,KAAKU,aAAL,CAAmB,WAAnB,CAAP,EAAwCE,GAAxC,CAA4CD,QAA5C;AACA;AACA;AACAF,WAAO6B,QAAQ5B,aAAR,CAAsB,oBAAtB,CAAP,EAAoDE,GAApD,CAAwDD,QAAxD;AACAF,WAAO6B,QAAQ5B,aAAR,CAAsB,iBAAtB,EAAyCiC,WAAhD,EAA6DD,IAA7D,CACE,YADF;AAGAjC,WAAO6B,QAAQ5B,aAAR,CAAsB,gBAAtB,CAAP,EAAgDC,QAAhD;AACAF,WAAO6B,QAAQ5B,aAAR,CAAsB,oBAAtB,CAAP,EAAoDC,QAApD;;AAEA;AACAzB,kBAAcC,IAAd,EAAoBR,SAApB;AACA8B,WAAOT,KAAKU,aAAL,CAAmB,oBAAnB,CAAP,EAAiDC,QAAjD;AACD,GAzBD;;AA2BAH,KAAG,iDAAH,EAAsD,YAAW;AAC/D,QAAMR,OAAOG,SAASZ,aAAT,CAAuB,KAAvB,CAAb;AACA,oBAAI,YAAM;AACR,8BAAWS,IAAX,EAAiBX,MAAjB,CAAwBC,gBAAMC,aAAN,CAAoBqD,iCAApB,EAAyC,IAAzC,CAAxB;AACD,KAFD;AAGAnC,WAAOT,KAAKU,aAAL,CAAmB,oBAAnB,CAAP,EAAiDE,GAAjD,CAAqDD,QAArD;AACAF,WAAOT,KAAKU,aAAL,CAAmB,oBAAnB,CAAP,EAAiDE,GAAjD,CAAqDD,QAArD;AACAF,WAAOT,KAAKU,aAAL,CAAmB,oBAAnB,CAAP,EAAiDC,QAAjD;AACAF,WAAOT,KAAKU,aAAL,CAAmB,oBAAnB,CAAP,EAAiDC,QAAjD;AACAF,WAAOT,KAAKU,aAAL,CAAmB,iBAAnB,EAAsCiC,WAA7C,EAA0DD,IAA1D,CACE,YADF;AAGD,GAZD;;AAcAlC,KAAG,wEAAH,EAA6E,YAAW;AACtF,QAAMqC,OAAO,SAAPA,IAAO;AAAA,aAAM,IAAIC,OAAJ,CAAY;AAAA,eAAWC,WAAWC,OAAX,EAAoBC,EAApB,CAAX;AAAA,OAAZ,CAAN;AAAA,KAAb;AACA;AACA;AACA,QAAMC,WAAW,SAAXA,QAAW;AAAA,aACf,IAAIJ,OAAJ,CAAY,UAACE,OAAD,EAAUG,MAAV;AAAA,eAAqB,gBAAIC,QAAJ,EAAcC,IAAd,CAAmBL,OAAnB,EAA4BG,MAA5B,CAArB;AAAA,OAAZ,CADe;AAAA,KAAjB;AAEA,QAAMG,kBAAkB,EAAxB;;AANsF,QAOhFC,UAPgF;AAQpF,0BAAYC,GAAZ,EAAiB;AAAA;;AACf,aAAKA,GAAL,GAAWA,GAAX;AACA,aAAKC,MAAL,GAAc,EAAd;AACA,aAAKC,SAAL,GAAiB,IAAjB;AACAJ,wBAAgB/C,IAAhB,CAAqB,IAArB;AACD;;AAbmF;AAAA;AAAA,oCAexE0B,OAfwE,EAe/D;AACnB,eAAKwB,MAAL,CAAYlD,IAAZ,CAAiB0B,OAAjB;AACD;AAjBmF;AAAA;AAAA,oCAmBxE,CAAE;AAnBsE;;AAAA;AAAA;;AAsBtF,QAAM0B,iBAAiBvF,OAAO0C,MAA9B;AACA1C,WAAO0C,MAAP,GAAgByC,UAAhB;;AAEA;AACA,QAAMnE,QAAQgC,OAAOC,MAAP,CAAc,EAAd,EAAkB1C,SAAlB,EAA6B,EAACiF,iBAAiB,CAAlB,EAA7B,CAAd;;AA1BsF,kBA2BvE1D,MAAMd,KAAN,CA3BuE;AAAA,QA2B/EY,IA3B+E,WA2B/EA,IA3B+E;;AA6BtF,QAAM6D,UAAU,SAAVA,OAAU,GAAM;AACpBzF,aAAO0C,MAAP,GAAgB6C,cAAhB;AACD,KAFD;;AAIA;AACAlD,WAAOT,KAAKU,aAAL,CAAmB,oBAAnB,CAAP,EAAiDE,GAAjD,CAAqDD,QAArD;;AAEA;AACA,WAAOuC,SAAS;AAAA,aAAML,KAAKiB,mCAAqB,EAA1B,CAAN;AAAA,KAAT,EACJT,IADI,CACC,YAAM;AACV,UAAMU,SAAST,gBAAgB,CAAhB,CAAf;AACA7C,aAAOsD,MAAP,EAAeC,WAAf;AACA,UAAMC,aAAaF,OAAON,MAAP,CAAcS,IAAd,CAAmB;AAAA,eAAKC,EAAEC,IAAF,KAAW,eAAhB;AAAA,OAAnB,CAAnB;AACA3D,aAAOwD,UAAP,EAAmBD,WAAnB;AACA;AACAvD,aAAOT,KAAKU,aAAL,CAAmB,oBAAnB,CAAP,EAAiDE,GAAjD,CAAqDD,QAArD;;AAEA;AACA,UAAM0D,SAAS,qCACb,mCAAgB/F,OAAhB,EAAyB,EAAzB,CADa,EAEb,sCAAmBc,KAAnB,CAFa,CAAf;AAIA,aAAO8D,SAAS,YAAM;AACpBa,eAAOL,SAAP,CAAiB;AACf9E,gBAAM,EAACwF,MAAM,cAAP,EAAuBE,IAAIL,WAAWK,EAAtC,EAA0CD,cAA1C;AADS,SAAjB;AAGA,eAAOxB,KAAK,CAAL,CAAP;AACD,OALM,CAAP;AAMD,KApBI,EAqBJQ,IArBI,CAqBC,YAAM;AACV;AACA;AACA5C,aAAOT,KAAKU,aAAL,CAAmB,oBAAnB,CAAP,EAAiDC,QAAjD;AACAF,aAAOT,KAAKU,aAAL,CAAmB,WAAnB,CAAP,EAAwCE,GAAxC,CAA4CD,QAA5C;AACAkD;AACD,KA3BI,EA4BJU,KA5BI,CA4BE,iBAAS;AACdV;AACA,YAAMW,KAAN;AACD,KA/BI,CAAP;AAgCD,GArED;AAsED,CA1KD","file":"PivotTableUI-processing-test.js","sourcesContent":["import React, {act} from 'react';\nimport {createRoot} from 'react-dom/client';\nimport PivotTableUI, {PivotLoadingOverlay} from '../PivotTableUI';\nimport {\n computePivotState,\n createWorkerConfig,\n materializeData,\n WORKER_DEBOUNCE_MS,\n} from '../pivotCompute';\n/* eslint-disable no-magic-numbers */\n\n// React 19 needs to be told that this environment supports `act`.\nglobal.IS_REACT_ACT_ENVIRONMENT = true;\n\n// `showProcessing` is a debugging/testing hook that forces the loading\n// overlay on top of the rendered table without running a real worker\n// computation, so the overlay can be inspected while consuming the package.\nconst records = [\n {name: 'Nick', gender: 'male', colour: 'blue', trials: 103},\n {name: 'Jane', gender: 'female', colour: 'red', trials: 95},\n {name: 'John', gender: 'male', colour: 'blue', trials: 112},\n {name: 'Carol', gender: 'female', colour: 'yellow', trials: 102},\n];\n\nconst baseProps = {\n data: records,\n rows: ['name'],\n cols: [],\n aggregatorName: 'Count',\n vals: [],\n rendererName: 'Table',\n};\n\nfunction rerenderPivot(root, props) {\n act(() => {\n root.render(React.createElement(PivotTableUI, props));\n });\n}\n\ndescribe(' PivotTableUI showProcessing', function() {\n let containers;\n\n beforeEach(function() {\n containers = [];\n });\n\n afterEach(function() {\n containers.forEach(container => {\n act(() => {\n container.root.unmount();\n });\n container.node.remove();\n });\n });\n\n const mount = props => {\n const node = document.createElement('div');\n document.body.appendChild(node);\n const root = createRoot(node);\n act(() => {\n root.render(React.createElement(PivotTableUI, props));\n });\n const entry = {node, root};\n containers.push(entry);\n return entry;\n };\n\n it('does not render the overlay by default', function() {\n const {node} = mount(baseProps);\n expect(node.querySelector('.pvtLoadingOverlay')).toBeNull();\n expect(node.querySelector('.pvtTable')).not.toBeNull();\n });\n\n it('does not pass undefined attrValues while the worker is pending', function() {\n const originalWorker = global.Worker;\n const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => {});\n global.Worker = class PendingWorker {\n postMessage() {}\n terminate() {}\n };\n try {\n mount(\n Object.assign({}, baseProps, {\n data: new Array(201).fill(null).map((_, index) => ({\n name: `Employee ${index}`,\n })),\n })\n );\n const warnings = errorSpy.mock.calls\n .map(call => call.join(' '))\n .filter(message => message.includes('attrValues'));\n expect(warnings).toEqual([]);\n } finally {\n global.Worker = originalWorker;\n errorSpy.mockRestore();\n }\n });\n\n it('renders the overlay on top of the table when showProcessing is true', function() {\n const {node, root} = mount(baseProps);\n // Table is rendered from the real data first (no overlay).\n expect(node.querySelector('.pvtTable')).not.toBeNull();\n expect(node.querySelector('.pvtLoadingOverlay')).toBeNull();\n\n rerenderPivot(root, Object.assign({}, baseProps, {showProcessing: true}));\n\n const overlay = node.querySelector('.pvtLoadingOverlay');\n expect(overlay).not.toBeNull();\n expect(overlay.parentElement.classList.contains('pvtOutput')).toBe(true);\n // The overlay is layered on top of the table: the table must survive.\n expect(node.querySelector('.pvtTable')).not.toBeNull();\n // Only a spinner and a label: progress percentages were removed, the\n // overlay simply stays until the worker posts its result event.\n expect(overlay.querySelector('.pvtLoadingSpinner')).not.toBeNull();\n expect(overlay.querySelector('.pvtLoadingText').textContent).toBe(\n 'Processing'\n );\n expect(overlay.querySelector('.pvtLoadingBar')).toBeNull();\n expect(overlay.querySelector('.pvtLoadingPercent')).toBeNull();\n\n // Turning the flag back off removes the overlay.\n rerenderPivot(root, baseProps);\n expect(node.querySelector('.pvtLoadingOverlay')).toBeNull();\n });\n\n it('renders a spinner without any percentage markup', function() {\n const node = document.createElement('div');\n act(() => {\n createRoot(node).render(React.createElement(PivotLoadingOverlay, null));\n });\n expect(node.querySelector('.pvtLoadingOverlay')).not.toBeNull();\n expect(node.querySelector('.pvtLoadingSpinner')).not.toBeNull();\n expect(node.querySelector('.pvtLoadingBarWrap')).toBeNull();\n expect(node.querySelector('.pvtLoadingPercent')).toBeNull();\n expect(node.querySelector('.pvtLoadingText').textContent).toBe(\n 'Processing'\n );\n });\n\n it('hides the overlay only after the worker responds and the table renders', function() {\n const wait = ms => new Promise(resolve => setTimeout(resolve, ms));\n // React's act() returns a non-standard thenable whose .then() does not\n // return a promise, so it cannot be chained directly - wrap it first.\n const actAsync = callback =>\n new Promise((resolve, reject) => act(callback).then(resolve, reject));\n const workerInstances = [];\n class FakeWorker {\n constructor(url) {\n this.url = url;\n this.posted = [];\n this.onmessage = null;\n workerInstances.push(this);\n }\n\n postMessage(message) {\n this.posted.push(message);\n }\n\n terminate() {}\n }\n\n const previousWorker = global.Worker;\n global.Worker = FakeWorker;\n\n // workerThreshold: 2 makes this small dataset worker-eligible.\n const props = Object.assign({}, baseProps, {workerThreshold: 2});\n const {node} = mount(props);\n\n const restore = () => {\n global.Worker = previousWorker;\n };\n\n // The overlay is up while the computation is pending.\n expect(node.querySelector('.pvtLoadingOverlay')).not.toBeNull();\n\n // Wait out the dispatch debounce so the request reaches the worker.\n return actAsync(() => wait(WORKER_DEBOUNCE_MS + 50))\n .then(() => {\n const worker = workerInstances[0];\n expect(worker).toBeDefined();\n const computeMsg = worker.posted.find(m => m.type === 'pivot:compute');\n expect(computeMsg).toBeDefined();\n // The worker has not answered yet: the overlay must stay up.\n expect(node.querySelector('.pvtLoadingOverlay')).not.toBeNull();\n\n // Worker finishes and posts its result event.\n const result = computePivotState(\n materializeData(records, {}),\n createWorkerConfig(props)\n );\n return actAsync(() => {\n worker.onmessage({\n data: {type: 'pivot:result', id: computeMsg.id, result},\n });\n return wait(0);\n });\n })\n .then(() => {\n // The overlay is gone only now - and the freshly computed table is\n // already on screen in the same state where the overlay disappeared.\n expect(node.querySelector('.pvtLoadingOverlay')).toBeNull();\n expect(node.querySelector('.pvtTable')).not.toBeNull();\n restore();\n })\n .catch(error => {\n restore();\n throw error;\n });\n });\n});\n"]}
|
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }();
|
|
4
|
+
|
|
3
5
|
var _react = require('react');
|
|
4
6
|
|
|
5
7
|
var _react2 = _interopRequireDefault(_react);
|
|
6
8
|
|
|
7
9
|
var _client = require('react-dom/client');
|
|
8
10
|
|
|
11
|
+
var _tips = require('../../examples/tips');
|
|
12
|
+
|
|
13
|
+
var _tips2 = _interopRequireDefault(_tips);
|
|
14
|
+
|
|
9
15
|
var _PivotTable = require('../PivotTable');
|
|
10
16
|
|
|
11
17
|
var _PivotTable2 = _interopRequireDefault(_PivotTable);
|
|
@@ -14,15 +20,33 @@ var _PivotTableUI = require('../PivotTableUI');
|
|
|
14
20
|
|
|
15
21
|
var _PivotTableUI2 = _interopRequireDefault(_PivotTableUI);
|
|
16
22
|
|
|
23
|
+
var _TableRenderers = require('../TableRenderers');
|
|
24
|
+
|
|
25
|
+
var _PivotDataWorker = require('../PivotDataWorker');
|
|
26
|
+
|
|
27
|
+
var PivotDataWorker = _interopRequireWildcard(_PivotDataWorker);
|
|
28
|
+
|
|
29
|
+
var _pivotCompute = require('../pivotCompute');
|
|
30
|
+
|
|
31
|
+
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
|
|
32
|
+
|
|
17
33
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
18
34
|
|
|
19
35
|
/* eslint-disable no-magic-numbers */
|
|
20
36
|
|
|
21
37
|
// React 19 needs to be told that this environment supports `act`.
|
|
22
38
|
global.IS_REACT_ACT_ENVIRONMENT = true;
|
|
39
|
+
global.queueMicrotask = function (callback) {
|
|
40
|
+
return Promise.resolve().then(callback);
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
var _require = require('react-dom/server'),
|
|
44
|
+
renderToStaticMarkup = _require.renderToStaticMarkup;
|
|
23
45
|
|
|
24
46
|
// `showNumericalOrder` adds a "No." column in front of the row attributes so
|
|
25
47
|
// every data row is prefixed with its 1-based index.
|
|
48
|
+
|
|
49
|
+
|
|
26
50
|
var records = [{ name: 'Nick', gender: 'male', colour: 'blue', trials: 103 }, { name: 'Jane', gender: 'female', colour: 'red', trials: 95 }, { name: 'John', gender: 'male', colour: 'blue', trials: 112 }, { name: 'Carol', gender: 'female', colour: 'yellow', trials: 102 }];
|
|
27
51
|
|
|
28
52
|
var baseProps = {
|
|
@@ -174,5 +198,430 @@ describe('Table renderer showNumericalOrder', function () {
|
|
|
174
198
|
expect(numberCells(mounted.node)).toEqual(['1', '2', '3', '4']);
|
|
175
199
|
});
|
|
176
200
|
});
|
|
201
|
+
|
|
202
|
+
it('renders only visible rows and updates them while scrolling', function () {
|
|
203
|
+
var manyRecords = Array.from({ length: 1000 }, function (_, index) {
|
|
204
|
+
return {
|
|
205
|
+
name: 'Employee ' + String(index).padStart(4, '0')
|
|
206
|
+
};
|
|
207
|
+
});
|
|
208
|
+
var previousAnimationFrame = global.requestAnimationFrame;
|
|
209
|
+
var pendingFrame = void 0;
|
|
210
|
+
global.requestAnimationFrame = function (callback) {
|
|
211
|
+
pendingFrame = callback;
|
|
212
|
+
return 1;
|
|
213
|
+
};
|
|
214
|
+
jest.useFakeTimers();
|
|
215
|
+
try {
|
|
216
|
+
mounted = mount(_react2.default.createElement(_PivotTable2.default, Object.assign({}, baseProps, {
|
|
217
|
+
data: manyRecords,
|
|
218
|
+
showNumericalOrder: true,
|
|
219
|
+
virtualizeRows: true
|
|
220
|
+
})));
|
|
221
|
+
|
|
222
|
+
var table = mounted.node.querySelector('.pvtTable');
|
|
223
|
+
expect(table.getAttribute('data-pvt-virtualized')).toBe('true');
|
|
224
|
+
expect(table.querySelectorAll('tbody .pvtDataRow').length).toBeLessThan(150);
|
|
225
|
+
expect(numberCells(mounted.node)[0]).toBe('1');
|
|
226
|
+
|
|
227
|
+
var body = table.querySelector('tbody');
|
|
228
|
+
body.getBoundingClientRect = function () {
|
|
229
|
+
return { top: -3200 };
|
|
230
|
+
};
|
|
231
|
+
(0, _react.act)(function () {
|
|
232
|
+
window.dispatchEvent(new Event('scroll'));
|
|
233
|
+
if (pendingFrame) {
|
|
234
|
+
pendingFrame();
|
|
235
|
+
}
|
|
236
|
+
});
|
|
237
|
+
expect(numberCells(mounted.node)[0]).toBe('1');
|
|
238
|
+
expect(mounted.node.querySelector('.pvtVirtualScrollOverlay .pvtLoadingText').textContent).toBe('Processing');
|
|
239
|
+
(0, _react.act)(function () {
|
|
240
|
+
return jest.runTimersToTime(499);
|
|
241
|
+
});
|
|
242
|
+
expect(numberCells(mounted.node)[0]).toBe('1');
|
|
243
|
+
(0, _react.act)(function () {
|
|
244
|
+
return jest.runTimersToTime(1);
|
|
245
|
+
});
|
|
246
|
+
expect(numberCells(mounted.node)[0]).toBe('65');
|
|
247
|
+
expect(mounted.node.querySelector('.pvtVirtualScrollOverlay')).toBeNull();
|
|
248
|
+
expect(table.querySelectorAll('tbody .pvtDataRow').length).toBeLessThan(150);
|
|
249
|
+
} finally {
|
|
250
|
+
global.requestAnimationFrame = previousAnimationFrame;
|
|
251
|
+
jest.useRealTimers();
|
|
252
|
+
}
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
it('does not update synchronously again when layout shifts during a fast scroll', function () {
|
|
256
|
+
var manyRecords = Array.from({ length: 1000 }, function (_, index) {
|
|
257
|
+
return {
|
|
258
|
+
name: 'Employee ' + index
|
|
259
|
+
};
|
|
260
|
+
});
|
|
261
|
+
var fullPrecomputedData = (0, _pivotCompute.computePivotState)((0, _pivotCompute.materializeData)(manyRecords, {}), (0, _pivotCompute.createWorkerConfig)(baseProps));
|
|
262
|
+
var precomputedData = (0, _pivotCompute.createVirtualPivotSummary)(fullPrecomputedData, false);
|
|
263
|
+
precomputedData.viewportKey = 42;
|
|
264
|
+
var layoutReads = 0;
|
|
265
|
+
var previousAnimationFrame = global.requestAnimationFrame;
|
|
266
|
+
var pendingFrame = void 0;
|
|
267
|
+
global.requestAnimationFrame = function (callback) {
|
|
268
|
+
pendingFrame = callback;
|
|
269
|
+
return 1;
|
|
270
|
+
};
|
|
271
|
+
jest.useFakeTimers();
|
|
272
|
+
try {
|
|
273
|
+
mounted = mount(_react2.default.createElement(_PivotTable2.default, Object.assign({}, baseProps, {
|
|
274
|
+
data: [],
|
|
275
|
+
precomputedData: precomputedData,
|
|
276
|
+
virtualizeRows: true
|
|
277
|
+
})));
|
|
278
|
+
|
|
279
|
+
var body = mounted.node.querySelector('.pvtTable tbody');
|
|
280
|
+
body.getBoundingClientRect = function () {
|
|
281
|
+
return {
|
|
282
|
+
top: layoutReads++ % 2 === 0 ? -3200 : -6400
|
|
283
|
+
};
|
|
284
|
+
};
|
|
285
|
+
(0, _react.act)(function () {
|
|
286
|
+
window.dispatchEvent(new Event('scroll'));
|
|
287
|
+
if (pendingFrame) {
|
|
288
|
+
pendingFrame();
|
|
289
|
+
}
|
|
290
|
+
});
|
|
291
|
+
expect(layoutReads).toBe(0);
|
|
292
|
+
(0, _react.act)(function () {
|
|
293
|
+
return jest.runTimersToTime(250);
|
|
294
|
+
});
|
|
295
|
+
(0, _react.act)(function () {
|
|
296
|
+
window.dispatchEvent(new Event('scroll'));
|
|
297
|
+
});
|
|
298
|
+
(0, _react.act)(function () {
|
|
299
|
+
return jest.runTimersToTime(499);
|
|
300
|
+
});
|
|
301
|
+
expect(layoutReads).toBe(0);
|
|
302
|
+
(0, _react.act)(function () {
|
|
303
|
+
return jest.runTimersToTime(1);
|
|
304
|
+
});
|
|
305
|
+
expect(layoutReads).toBe(1);
|
|
306
|
+
(0, _react.act)(function () {
|
|
307
|
+
return window.dispatchEvent(new Event('scroll'));
|
|
308
|
+
});
|
|
309
|
+
(0, _react.act)(function () {
|
|
310
|
+
return jest.runTimersToTime(500);
|
|
311
|
+
});
|
|
312
|
+
expect(layoutReads).toBe(2);
|
|
313
|
+
} finally {
|
|
314
|
+
global.requestAnimationFrame = previousAnimationFrame;
|
|
315
|
+
jest.useRealTimers();
|
|
316
|
+
}
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
it('renders only the visible columns and updates them after horizontal scrolling', function () {
|
|
320
|
+
var wideRecords = Array.from({ length: 200 }, function (_, index) {
|
|
321
|
+
return {
|
|
322
|
+
employee: 'Employee ' + String(index).padStart(3, '0'),
|
|
323
|
+
gender: index % 2 === 0 ? 'female' : 'male'
|
|
324
|
+
};
|
|
325
|
+
});
|
|
326
|
+
jest.useFakeTimers();
|
|
327
|
+
try {
|
|
328
|
+
mounted = mount(_react2.default.createElement(_PivotTable2.default, Object.assign({}, baseProps, {
|
|
329
|
+
data: wideRecords,
|
|
330
|
+
rows: ['gender'],
|
|
331
|
+
cols: ['employee'],
|
|
332
|
+
virtualizeRows: true
|
|
333
|
+
})));
|
|
334
|
+
|
|
335
|
+
var table = mounted.node.querySelector('.pvtTable');
|
|
336
|
+
var initialLabels = Array.from(table.querySelectorAll('thead .pvtColLabel')).map(function (cell) {
|
|
337
|
+
return cell.textContent.trim();
|
|
338
|
+
});
|
|
339
|
+
expect(table.classList.contains('pvtVirtualColumns')).toBe(true);
|
|
340
|
+
expect(initialLabels).toContain('Employee 000');
|
|
341
|
+
expect(initialLabels).not.toContain('Employee 150');
|
|
342
|
+
expect(table.querySelectorAll('tbody .pvtVal').length).toBeLessThan(100);
|
|
343
|
+
|
|
344
|
+
var body = table.querySelector('tbody');
|
|
345
|
+
body.getBoundingClientRect = function () {
|
|
346
|
+
return { top: 0, left: -16000 };
|
|
347
|
+
};
|
|
348
|
+
(0, _react.act)(function () {
|
|
349
|
+
return window.dispatchEvent(new Event('scroll'));
|
|
350
|
+
});
|
|
351
|
+
(0, _react.act)(function () {
|
|
352
|
+
return jest.runTimersToTime(500);
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
var scrolledLabels = Array.from(table.querySelectorAll('thead .pvtColLabel')).map(function (cell) {
|
|
356
|
+
return cell.textContent.trim();
|
|
357
|
+
});
|
|
358
|
+
expect(scrolledLabels).not.toContain('Employee 000');
|
|
359
|
+
expect(scrolledLabels.some(function (label) {
|
|
360
|
+
return label >= 'Employee 128';
|
|
361
|
+
})).toBe(true);
|
|
362
|
+
expect(table.querySelectorAll('tbody .pvtVal').length).toBeLessThan(100);
|
|
363
|
+
} finally {
|
|
364
|
+
jest.useRealTimers();
|
|
365
|
+
}
|
|
366
|
+
});
|
|
367
|
+
|
|
368
|
+
it('renders values after moving a high-cardinality field from rows to columns', function () {
|
|
369
|
+
var wait = function wait(ms) {
|
|
370
|
+
return new Promise(function (resolve) {
|
|
371
|
+
return setTimeout(resolve, ms);
|
|
372
|
+
});
|
|
373
|
+
};
|
|
374
|
+
var actAsync = function actAsync(callback) {
|
|
375
|
+
return new Promise(function (resolve, reject) {
|
|
376
|
+
return (0, _react.act)(callback).then(resolve, reject);
|
|
377
|
+
});
|
|
378
|
+
};
|
|
379
|
+
var manyRecords = Array.from({ length: 400 }, function (_, index) {
|
|
380
|
+
return {
|
|
381
|
+
employee: 'Employee ' + String(index).padStart(3, '0'),
|
|
382
|
+
rowLabel: 'Row ' + String(399 - index).padStart(3, '0')
|
|
383
|
+
};
|
|
384
|
+
});
|
|
385
|
+
var aggregation = [{ key: 'count', aggregatorName: 'Count', vals: [] }];
|
|
386
|
+
var rowConfig = {
|
|
387
|
+
rows: ['employee'],
|
|
388
|
+
cols: [],
|
|
389
|
+
aggregations: aggregation
|
|
390
|
+
};
|
|
391
|
+
var columnConfig = {
|
|
392
|
+
rows: ['rowLabel'],
|
|
393
|
+
cols: ['employee'],
|
|
394
|
+
aggregations: aggregation
|
|
395
|
+
};
|
|
396
|
+
var materialized = (0, _pivotCompute.materializeData)(manyRecords, {});
|
|
397
|
+
var rowPivot = (0, _pivotCompute.computePivotState)(materialized, rowConfig);
|
|
398
|
+
var columnPivot = (0, _pivotCompute.computePivotState)(materialized, columnConfig);
|
|
399
|
+
expect((0, _pivotCompute.alignSparseColumnsToRows)(columnPivot)).toBe(true);
|
|
400
|
+
var rowSummary = (0, _pivotCompute.createVirtualPivotSummary)(rowPivot, false);
|
|
401
|
+
var columnSummary = (0, _pivotCompute.createVirtualPivotSummary)(columnPivot, false);
|
|
402
|
+
rowSummary.viewportKey = 41;
|
|
403
|
+
columnSummary.viewportKey = 42;
|
|
404
|
+
var workerSpy = jest.spyOn(PivotDataWorker, 'computePivotViewportInWorker').mockImplementation(function (viewportKey, start, end, columnMode, columnStart, columnEnd) {
|
|
405
|
+
return Promise.resolve((0, _pivotCompute.computePivotViewport)(viewportKey === 41 ? rowPivot : columnPivot, start, end, columnMode, columnStart, columnEnd));
|
|
406
|
+
});
|
|
407
|
+
|
|
408
|
+
mounted = mount(_react2.default.createElement(_PivotTable2.default, Object.assign({}, baseProps, rowConfig, {
|
|
409
|
+
data: [],
|
|
410
|
+
precomputedData: rowSummary,
|
|
411
|
+
virtualizeRows: true
|
|
412
|
+
})));
|
|
413
|
+
|
|
414
|
+
return actAsync(function () {
|
|
415
|
+
return wait(30);
|
|
416
|
+
}).then(function () {
|
|
417
|
+
(0, _react.act)(function () {
|
|
418
|
+
// A layout-induced scroll can still be pending when the new worker
|
|
419
|
+
// result replaces the previous axis configuration. The new viewport
|
|
420
|
+
// must reset immediately instead of retaining an empty 0..0 column
|
|
421
|
+
// window until the scroll debounce expires.
|
|
422
|
+
window.dispatchEvent(new Event('scroll'));
|
|
423
|
+
mounted.root.render(_react2.default.createElement(_PivotTable2.default, Object.assign({}, baseProps, columnConfig, {
|
|
424
|
+
data: [],
|
|
425
|
+
precomputedData: columnSummary,
|
|
426
|
+
virtualizeRows: true
|
|
427
|
+
})));
|
|
428
|
+
});
|
|
429
|
+
return actAsync(function () {
|
|
430
|
+
return wait(50);
|
|
431
|
+
});
|
|
432
|
+
}).then(function () {
|
|
433
|
+
var values = Array.from(mounted.node.querySelectorAll('.pvtTable tbody .pvtVal')).map(function (cell) {
|
|
434
|
+
return cell.textContent.trim();
|
|
435
|
+
});
|
|
436
|
+
expect(values.length).toBeGreaterThan(0);
|
|
437
|
+
expect(values).toContain('1');
|
|
438
|
+
expect(mounted.node.querySelector('.pvtVirtualLoading')).toBeNull();
|
|
439
|
+
workerSpy.mockRestore();
|
|
440
|
+
}).catch(function (error) {
|
|
441
|
+
workerSpy.mockRestore();
|
|
442
|
+
throw error;
|
|
443
|
+
});
|
|
444
|
+
});
|
|
445
|
+
|
|
446
|
+
it('renders Employee Ref headers and cells for the example configuration', function () {
|
|
447
|
+
var wait = function wait(ms) {
|
|
448
|
+
return new Promise(function (resolve) {
|
|
449
|
+
return setTimeout(resolve, ms);
|
|
450
|
+
});
|
|
451
|
+
};
|
|
452
|
+
var actAsync = function actAsync(callback) {
|
|
453
|
+
return new Promise(function (resolve, reject) {
|
|
454
|
+
return (0, _react.act)(callback).then(resolve, reject);
|
|
455
|
+
});
|
|
456
|
+
};
|
|
457
|
+
var appRows = ['Full Name Local', 'Full Name English', 'Gender', 'Joining Date', 'Last Working Date', 'Seniority Date', 'Contract Type', 'Location Name', 'Job Position Name', 'Cost Center Code', 'Cost Center Name', 'Organization Element Name', 'Nationality', 'Bank Account Number', 'Bank Name', 'Bank Account Holder Name', 'First Name Local', 'First Name English', 'Date Of Birth', 'Passport No.', 'Martial Status', 'Tax Code', 'Social Security No.', 'Pension Fund No'];
|
|
458
|
+
var appConfig = {
|
|
459
|
+
rows: appRows,
|
|
460
|
+
cols: ['Employee Ref'],
|
|
461
|
+
aggregations: [{ key: 'count', aggregatorName: 'Count', vals: [] }]
|
|
462
|
+
};
|
|
463
|
+
var fullPivot = (0, _pivotCompute.computePivotState)((0, _pivotCompute.materializeData)(_tips2.default, {}), appConfig);
|
|
464
|
+
expect((0, _pivotCompute.alignSparseColumnsToRows)(fullPivot)).toBe(true);
|
|
465
|
+
var summary = (0, _pivotCompute.createVirtualPivotSummary)(fullPivot, false);
|
|
466
|
+
summary.viewportKey = 43;
|
|
467
|
+
var workerSpy = jest.spyOn(PivotDataWorker, 'computePivotViewportInWorker').mockImplementation(function (viewportKey, start, end, columnMode, columnStart, columnEnd) {
|
|
468
|
+
return Promise.resolve((0, _pivotCompute.computePivotViewport)(fullPivot, start, end, columnMode, columnStart, columnEnd));
|
|
469
|
+
});
|
|
470
|
+
|
|
471
|
+
mounted = mount(_react2.default.createElement(_PivotTable2.default, Object.assign({}, baseProps, appConfig, {
|
|
472
|
+
data: [],
|
|
473
|
+
precomputedData: summary,
|
|
474
|
+
virtualizeRows: true
|
|
475
|
+
})));
|
|
476
|
+
|
|
477
|
+
return actAsync(function () {
|
|
478
|
+
return wait(50);
|
|
479
|
+
}).then(function () {
|
|
480
|
+
var headers = Array.from(mounted.node.querySelectorAll('.pvtTable thead .pvtColLabel')).map(function (cell) {
|
|
481
|
+
return cell.textContent.trim();
|
|
482
|
+
});
|
|
483
|
+
var values = Array.from(mounted.node.querySelectorAll('.pvtTable tbody .pvtVal')).map(function (cell) {
|
|
484
|
+
return cell.textContent.trim();
|
|
485
|
+
});
|
|
486
|
+
expect(headers.length).toBeGreaterThan(0);
|
|
487
|
+
expect(headers[0]).toMatch(/-F$/);
|
|
488
|
+
expect(values).toContain('1');
|
|
489
|
+
var firstHeader = headers[0];
|
|
490
|
+
var table = mounted.node.querySelector('.pvtTable');
|
|
491
|
+
var body = table.querySelector('tbody');
|
|
492
|
+
var firstColumn = table.querySelector('thead .pvtColLabel');
|
|
493
|
+
table.getBoundingClientRect = function () {
|
|
494
|
+
return { top: 0, left: -5000 };
|
|
495
|
+
};
|
|
496
|
+
body.getBoundingClientRect = function () {
|
|
497
|
+
return { top: 0, left: -5000 };
|
|
498
|
+
};
|
|
499
|
+
firstColumn.getBoundingClientRect = function () {
|
|
500
|
+
return {
|
|
501
|
+
top: 0,
|
|
502
|
+
left: -1885,
|
|
503
|
+
width: 100
|
|
504
|
+
};
|
|
505
|
+
};
|
|
506
|
+
(0, _react.act)(function () {
|
|
507
|
+
return window.dispatchEvent(new Event('scroll'));
|
|
508
|
+
});
|
|
509
|
+
return actAsync(function () {
|
|
510
|
+
return wait(600);
|
|
511
|
+
}).then(function () {
|
|
512
|
+
var scrolledHeaders = Array.from(mounted.node.querySelectorAll('.pvtTable thead .pvtColLabel')).map(function (cell) {
|
|
513
|
+
return cell.textContent.trim();
|
|
514
|
+
});
|
|
515
|
+
expect(scrolledHeaders[0]).toBe(firstHeader);
|
|
516
|
+
workerSpy.mockRestore();
|
|
517
|
+
});
|
|
518
|
+
}).catch(function (error) {
|
|
519
|
+
workerSpy.mockRestore();
|
|
520
|
+
throw error;
|
|
521
|
+
});
|
|
522
|
+
});
|
|
523
|
+
|
|
524
|
+
it('can render every row for a full export from a virtual table', function () {
|
|
525
|
+
var manyRecords = Array.from({ length: 301 }, function (_, index) {
|
|
526
|
+
return {
|
|
527
|
+
name: 'Employee ' + index
|
|
528
|
+
};
|
|
529
|
+
});
|
|
530
|
+
var fullPrecomputedData = (0, _pivotCompute.computePivotState)((0, _pivotCompute.materializeData)(manyRecords, {}), (0, _pivotCompute.createWorkerConfig)(baseProps));
|
|
531
|
+
var precomputedData = (0, _pivotCompute.createVirtualPivotSummary)(fullPrecomputedData, false);
|
|
532
|
+
mounted = mount(_react2.default.createElement(_PivotTable2.default, Object.assign({}, baseProps, {
|
|
533
|
+
data: manyRecords,
|
|
534
|
+
precomputedData: precomputedData,
|
|
535
|
+
virtualizeRows: true
|
|
536
|
+
})));
|
|
537
|
+
|
|
538
|
+
var table = mounted.node.querySelector('.pvtTable');
|
|
539
|
+
var pivotProps = (0, _TableRenderers.getPivotTableProps)(table);
|
|
540
|
+
expect(table.querySelectorAll('tbody .pvtDataRow').length).toBeLessThan(301);
|
|
541
|
+
var html = renderToStaticMarkup(_react2.default.createElement(_PivotTable2.default, Object.assign({}, pivotProps, { virtualizeRows: false })));
|
|
542
|
+
var exportedTable = new DOMParser().parseFromString(html, 'text/html').querySelector('.pvtTable');
|
|
543
|
+
expect(exportedTable.querySelectorAll('tbody .pvtDataRow')).toHaveLength(301);
|
|
544
|
+
});
|
|
545
|
+
|
|
546
|
+
it('shows loading until the worker returns the requested row window', function () {
|
|
547
|
+
var wait = function wait(ms) {
|
|
548
|
+
return new Promise(function (resolve) {
|
|
549
|
+
return setTimeout(resolve, ms);
|
|
550
|
+
});
|
|
551
|
+
};
|
|
552
|
+
var actAsync = function actAsync(callback) {
|
|
553
|
+
return new Promise(function (resolve, reject) {
|
|
554
|
+
return (0, _react.act)(callback).then(resolve, reject);
|
|
555
|
+
});
|
|
556
|
+
};
|
|
557
|
+
var manyRecords = Array.from({ length: 301 }, function (_, index) {
|
|
558
|
+
return {
|
|
559
|
+
name: 'Employee ' + index
|
|
560
|
+
};
|
|
561
|
+
});
|
|
562
|
+
var fullPrecomputedData = (0, _pivotCompute.computePivotState)((0, _pivotCompute.materializeData)(manyRecords, {}), (0, _pivotCompute.createWorkerConfig)(baseProps));
|
|
563
|
+
var precomputedData = (0, _pivotCompute.createVirtualPivotSummary)(fullPrecomputedData, false);
|
|
564
|
+
precomputedData.viewportKey = 42;
|
|
565
|
+
var resolveWindows = [];
|
|
566
|
+
var workerSpy = jest.spyOn(PivotDataWorker, 'computePivotViewportInWorker').mockImplementation(function () {
|
|
567
|
+
return new Promise(function (resolve) {
|
|
568
|
+
resolveWindows.push(resolve);
|
|
569
|
+
});
|
|
570
|
+
});
|
|
571
|
+
|
|
572
|
+
mounted = mount(_react2.default.createElement(_PivotTable2.default, Object.assign({}, baseProps, {
|
|
573
|
+
data: [],
|
|
574
|
+
precomputedData: precomputedData,
|
|
575
|
+
virtualizeRows: true
|
|
576
|
+
})));
|
|
577
|
+
expect(mounted.node.querySelector('.pvtVirtualLoading')).not.toBeNull();
|
|
578
|
+
|
|
579
|
+
return actAsync(function () {
|
|
580
|
+
return wait(30);
|
|
581
|
+
}).then(function () {
|
|
582
|
+
expect(workerSpy).toHaveBeenCalledTimes(1);
|
|
583
|
+
var body = mounted.node.querySelector('.pvtTable tbody');
|
|
584
|
+
body.getBoundingClientRect = function () {
|
|
585
|
+
return { top: -3200 };
|
|
586
|
+
};
|
|
587
|
+
(0, _react.act)(function () {
|
|
588
|
+
return window.dispatchEvent(new Event('scroll'));
|
|
589
|
+
});
|
|
590
|
+
expect(mounted.node.querySelector('.pvtVirtualScrollOverlay .pvtLoadingText').textContent).toBe('Processing');
|
|
591
|
+
return actAsync(function () {
|
|
592
|
+
return wait(550);
|
|
593
|
+
});
|
|
594
|
+
}).then(function () {
|
|
595
|
+
expect(workerSpy).toHaveBeenCalledTimes(2);
|
|
596
|
+
expect(mounted.node.querySelector('.pvtVirtualLoading')).not.toBeNull();
|
|
597
|
+
|
|
598
|
+
var _workerSpy$mock$calls = _slicedToArray(workerSpy.mock.calls[0], 3),
|
|
599
|
+
start = _workerSpy$mock$calls[1],
|
|
600
|
+
end = _workerSpy$mock$calls[2];
|
|
601
|
+
|
|
602
|
+
return actAsync(function () {
|
|
603
|
+
resolveWindows[0]((0, _pivotCompute.computePivotViewport)(fullPrecomputedData, start, end, false));
|
|
604
|
+
return wait(0);
|
|
605
|
+
});
|
|
606
|
+
}).then(function () {
|
|
607
|
+
expect(mounted.node.querySelector('.pvtVirtualLoading')).not.toBeNull();
|
|
608
|
+
|
|
609
|
+
var _workerSpy$mock$calls2 = _slicedToArray(workerSpy.mock.calls[1], 3),
|
|
610
|
+
start = _workerSpy$mock$calls2[1],
|
|
611
|
+
end = _workerSpy$mock$calls2[2];
|
|
612
|
+
|
|
613
|
+
return actAsync(function () {
|
|
614
|
+
resolveWindows[1]((0, _pivotCompute.computePivotViewport)(fullPrecomputedData, start, end, false));
|
|
615
|
+
return wait(0);
|
|
616
|
+
});
|
|
617
|
+
}).then(function () {
|
|
618
|
+
expect(mounted.node.querySelector('.pvtVirtualLoading')).toBeNull();
|
|
619
|
+
expect(mounted.node.querySelectorAll('.pvtTable tbody .pvtDataRow').length).toBeGreaterThan(0);
|
|
620
|
+
workerSpy.mockRestore();
|
|
621
|
+
}).catch(function (error) {
|
|
622
|
+
workerSpy.mockRestore();
|
|
623
|
+
throw error;
|
|
624
|
+
});
|
|
625
|
+
});
|
|
177
626
|
});
|
|
178
627
|
//# sourceMappingURL=TableRenderers-showNumericalOrder-test.js.map
|