primekit 1.0.8 → 1.0.10
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/README.md +25 -25
- package/ng-package.json +8 -0
- package/package.json +12 -25
- package/src/assets/images/empty-table.svg +25 -25
- package/src/lib/lib/atomix-alert/atomix-alert.component.css +67 -0
- package/src/lib/lib/atomix-alert/atomix-alert.component.html +7 -0
- package/src/lib/lib/atomix-alert/atomix-alert.component.spec.ts +154 -0
- package/src/lib/lib/atomix-alert/atomix-alert.component.ts +75 -0
- package/src/lib/lib/atomix-autocomplete/atomix-autocomplete.component.html +35 -0
- package/src/lib/lib/atomix-autocomplete/atomix-autocomplete.component.scss +72 -0
- package/src/lib/lib/atomix-autocomplete/atomix-autocomplete.component.spec.ts +210 -0
- package/src/lib/lib/atomix-autocomplete/atomix-autocomplete.component.ts +70 -0
- package/src/lib/lib/atomix-button/atomix-button.component.css +70 -0
- package/src/lib/lib/atomix-button/atomix-button.component.html +20 -0
- package/src/lib/lib/atomix-button/atomix-button.component.spec.ts +135 -0
- package/src/lib/lib/atomix-button/atomix-button.component.ts +28 -0
- package/{lib/lib/atomix-button/atomix-button.models.d.ts → src/lib/lib/atomix-button/atomix-button.models.ts} +2 -2
- package/src/lib/lib/atomix-calendar/atomix-calendar.component.css +5 -0
- package/src/lib/lib/atomix-calendar/atomix-calendar.component.html +20 -0
- package/src/lib/lib/atomix-calendar/atomix-calendar.component.spec.ts +145 -0
- package/src/lib/lib/atomix-calendar/atomix-calendar.component.ts +71 -0
- package/src/lib/lib/atomix-card/atomix-card.component.css +4 -0
- package/src/lib/lib/atomix-card/atomix-card.component.html +3 -0
- package/src/lib/lib/atomix-card/atomix-card.component.spec.ts +63 -0
- package/src/lib/lib/atomix-card/atomix-card.component.ts +13 -0
- package/src/lib/lib/atomix-confirmation-dialog/atomix-confirmation-dialog.component.css +12 -0
- package/src/lib/lib/atomix-confirmation-dialog/atomix-confirmation-dialog.component.html +9 -0
- package/src/lib/lib/atomix-confirmation-dialog/atomix-confirmation-dialog.component.spec.ts +63 -0
- package/src/lib/lib/atomix-confirmation-dialog/atomix-confirmation-dialog.component.ts +22 -0
- package/src/lib/lib/atomix-daterange-calendar/atomix-daterange-calendar.component.html +233 -0
- package/src/lib/lib/atomix-daterange-calendar/atomix-daterange-calendar.component.scss +266 -0
- package/src/lib/lib/atomix-daterange-calendar/atomix-daterange-calendar.component.spec.ts +1465 -0
- package/src/lib/lib/atomix-daterange-calendar/atomix-daterange-calendar.component.ts +717 -0
- package/src/lib/lib/atomix-divider/atomix-divider.component.css +0 -0
- package/src/lib/lib/atomix-divider/atomix-divider.component.html +7 -0
- package/src/lib/lib/atomix-divider/atomix-divider.component.spec.ts +91 -0
- package/src/lib/lib/atomix-divider/atomix-divider.component.ts +17 -0
- package/src/lib/lib/atomix-dropdown/atomix-dropdown.component.css +25 -0
- package/src/lib/lib/atomix-dropdown/atomix-dropdown.component.html +37 -0
- package/src/lib/lib/atomix-dropdown/atomix-dropdown.component.spec.ts +178 -0
- package/src/lib/lib/atomix-dropdown/atomix-dropdown.component.ts +89 -0
- package/src/lib/lib/atomix-dynamic-dialog/atomix-dynamic-dialog.component.css +0 -0
- package/src/lib/lib/atomix-dynamic-dialog/atomix-dynamic-dialog.component.html +0 -0
- package/src/lib/lib/atomix-dynamic-dialog/atomix-dynamic-dialog.component.spec.ts +128 -0
- package/src/lib/lib/atomix-dynamic-dialog/atomix-dynamic-dialog.component.ts +42 -0
- package/src/lib/lib/atomix-dynamic-dialog/atomix-dynamic-dialog.models.ts +12 -0
- package/src/lib/lib/atomix-form/atomix-form-autocomplete/atomix-form-autocomplete.component.html +20 -0
- package/src/lib/lib/atomix-form/atomix-form-autocomplete/atomix-form-autocomplete.component.scss +7 -0
- package/src/lib/lib/atomix-form/atomix-form-autocomplete/atomix-form-autocomplete.component.spec.ts +169 -0
- package/src/lib/lib/atomix-form/atomix-form-autocomplete/atomix-form-autocomplete.component.ts +41 -0
- package/src/lib/lib/atomix-form/atomix-form-calendar/atomix-form-calendar.component.html +21 -0
- package/src/lib/lib/atomix-form/atomix-form-calendar/atomix-form-calendar.component.scss +7 -0
- package/src/lib/lib/atomix-form/atomix-form-calendar/atomix-form-calendar.component.spec.ts +142 -0
- package/src/lib/lib/atomix-form/atomix-form-calendar/atomix-form-calendar.component.ts +32 -0
- package/src/lib/lib/atomix-form/atomix-form-checkbox/atomix-form-checkbox.component.html +13 -0
- package/src/lib/lib/atomix-form/atomix-form-checkbox/atomix-form-checkbox.component.scss +14 -0
- package/src/lib/lib/atomix-form/atomix-form-checkbox/atomix-form-checkbox.component.spec.ts +112 -0
- package/src/lib/lib/atomix-form/atomix-form-checkbox/atomix-form-checkbox.component.ts +28 -0
- package/src/lib/lib/atomix-form/atomix-form-chips/atomix-form-chips.component.html +20 -0
- package/src/lib/lib/atomix-form/atomix-form-chips/atomix-form-chips.component.scss +3 -0
- package/src/lib/lib/atomix-form/atomix-form-chips/atomix-form-chips.component.spec.ts +153 -0
- package/src/lib/lib/atomix-form/atomix-form-chips/atomix-form-chips.component.ts +28 -0
- package/src/lib/lib/atomix-form/atomix-form-chips/form.chips.models.ts +5 -0
- package/src/lib/lib/atomix-form/atomix-form-dropdown/atomix-form-dropdown.component.html +24 -0
- package/src/lib/lib/atomix-form/atomix-form-dropdown/atomix-form-dropdown.component.scss +15 -0
- package/src/lib/lib/atomix-form/atomix-form-dropdown/atomix-form-dropdown.component.spec.ts +156 -0
- package/src/lib/lib/atomix-form/atomix-form-dropdown/atomix-form-dropdown.component.ts +36 -0
- package/src/lib/lib/atomix-form/atomix-form-input-component/atomix-form-input-component.component.html +33 -0
- package/src/lib/lib/atomix-form/atomix-form-input-component/atomix-form-input-component.component.scss +32 -0
- package/src/lib/lib/atomix-form/atomix-form-input-component/atomix-form-input-component.component.spec.ts +156 -0
- package/src/lib/lib/atomix-form/atomix-form-input-component/atomix-form-input-component.component.ts +42 -0
- package/src/lib/lib/atomix-form/atomix-form-inputmask-component/atomix-form-inputmask-component.component.html +14 -0
- package/src/lib/lib/atomix-form/atomix-form-inputmask-component/atomix-form-inputmask-component.component.scss +0 -0
- package/src/lib/lib/atomix-form/atomix-form-inputmask-component/atomix-form-inputmask-component.component.spec.ts +104 -0
- package/src/lib/lib/atomix-form/atomix-form-inputmask-component/atomix-form-inputmask-component.component.ts +24 -0
- package/src/lib/lib/atomix-form/atomix-form-password-component/atomix-form-password-component.component.html +16 -0
- package/src/lib/lib/atomix-form/atomix-form-password-component/atomix-form-password-component.component.scss +0 -0
- package/src/lib/lib/atomix-form/atomix-form-password-component/atomix-form-password-component.component.spec.ts +92 -0
- package/src/lib/lib/atomix-form/atomix-form-password-component/atomix-form-password-component.component.ts +24 -0
- package/src/lib/lib/atomix-form/atomix-form-radio-button/atomix-radio-button.component.html +23 -0
- package/src/lib/lib/atomix-form/atomix-form-radio-button/atomix-radio-button.component.scss +3 -0
- package/src/lib/lib/atomix-form/atomix-form-radio-button/atomix-radio-button.component.spec.ts +126 -0
- package/src/lib/lib/atomix-form/atomix-form-radio-button/atomix-radio-button.component.ts +26 -0
- package/src/lib/lib/atomix-form/atomix-form-textarea/atomix-form-textarea.component.html +17 -0
- package/src/lib/lib/atomix-form/atomix-form-textarea/atomix-form-textarea.component.scss +6 -0
- package/src/lib/lib/atomix-form/atomix-form-textarea/atomix-form-textarea.component.spec.ts +120 -0
- package/src/lib/lib/atomix-form/atomix-form-textarea/atomix-form-textarea.component.ts +24 -0
- package/src/lib/lib/atomix-input/atomix-input.component.css +52 -0
- package/src/lib/lib/atomix-input/atomix-input.component.html +45 -0
- package/src/lib/lib/atomix-input/atomix-input.component.spec.ts +229 -0
- package/src/lib/lib/atomix-input/atomix-input.component.ts +64 -0
- package/src/lib/lib/atomix-input-switch/atomix-input-switch.component.css +12 -0
- package/src/lib/lib/atomix-input-switch/atomix-input-switch.component.html +17 -0
- package/src/lib/lib/atomix-input-switch/atomix-input-switch.component.spec.ts +173 -0
- package/src/lib/lib/atomix-input-switch/atomix-input-switch.component.ts +62 -0
- package/src/lib/lib/atomix-loading-overlay/atomix-loading-overlay.component.html +47 -0
- package/src/lib/lib/atomix-loading-overlay/atomix-loading-overlay.component.scss +14 -0
- package/src/lib/lib/atomix-loading-overlay/atomix-loading-overlay.component.spec.ts +21 -0
- package/src/lib/lib/atomix-loading-overlay/atomix-loading-overlay.component.ts +25 -0
- package/src/lib/lib/atomix-messages/messages.component.css +0 -0
- package/src/lib/lib/atomix-messages/messages.component.html +9 -0
- package/src/lib/lib/atomix-messages/messages.component.spec.ts +115 -0
- package/src/lib/lib/atomix-messages/messages.component.ts +17 -0
- package/src/lib/lib/atomix-pagination/atomix-pagination.component.css +19 -0
- package/src/lib/lib/atomix-pagination/atomix-pagination.component.html +24 -0
- package/src/lib/lib/atomix-pagination/atomix-pagination.component.spec.ts +98 -0
- package/src/lib/lib/atomix-pagination/atomix-pagination.component.ts +36 -0
- package/src/lib/lib/atomix-radio-button/atomix-radio-button.component.css +0 -0
- package/src/lib/lib/atomix-radio-button/atomix-radio-button.component.html +7 -0
- package/src/lib/lib/atomix-radio-button/atomix-radio-button.component.spec.ts +116 -0
- package/src/lib/lib/atomix-radio-button/atomix-radio-button.component.ts +37 -0
- package/src/lib/lib/atomix-search-dropdown/atomix-search-dropdown.component.css +49 -0
- package/src/lib/lib/atomix-search-dropdown/atomix-search-dropdown.component.html +68 -0
- package/src/lib/lib/atomix-search-dropdown/atomix-search-dropdown.component.spec.ts +282 -0
- package/src/lib/lib/atomix-search-dropdown/atomix-search-dropdown.component.ts +119 -0
- package/{lib/lib/atomix-select-button/atomix-select-button-models.d.ts → src/lib/lib/atomix-select-button/atomix-select-button-models.ts} +4 -4
- package/src/lib/lib/atomix-select-button/atomix-select-button.component.css +5 -0
- package/src/lib/lib/atomix-select-button/atomix-select-button.component.html +7 -0
- package/src/lib/lib/atomix-select-button/atomix-select-button.component.spec.ts +73 -0
- package/src/lib/lib/atomix-select-button/atomix-select-button.component.ts +19 -0
- package/src/lib/lib/atomix-snackbar/atomix-snackbar.component.css +30 -0
- package/src/lib/lib/atomix-snackbar/atomix-snackbar.component.html +4 -0
- package/src/lib/lib/atomix-snackbar/atomix-snackbar.component.spec.ts +60 -0
- package/src/lib/lib/atomix-snackbar/atomix-snackbar.component.ts +27 -0
- package/src/lib/lib/atomix-spinner/atomix-spinner.component.css +0 -0
- package/src/lib/lib/atomix-spinner/atomix-spinner.component.html +7 -0
- package/src/lib/lib/atomix-spinner/atomix-spinner.component.spec.ts +70 -0
- package/src/lib/lib/atomix-spinner/atomix-spinner.component.ts +13 -0
- package/src/lib/lib/atomix-steps/atomix-steps.component.html +9 -0
- package/src/lib/lib/atomix-steps/atomix-steps.component.scss +0 -0
- package/src/lib/lib/atomix-steps/atomix-steps.component.spec.ts +120 -0
- package/src/lib/lib/atomix-steps/atomix-steps.component.ts +32 -0
- package/src/lib/lib/atomix-tabMenu/atomix-tabMenu.component.css +0 -0
- package/src/lib/lib/atomix-tabMenu/atomix-tabMenu.component.html +26 -0
- package/src/lib/lib/atomix-tabMenu/atomix-tabMenu.component.spec.ts +106 -0
- package/src/lib/lib/atomix-tabMenu/atomix-tabMenu.component.ts +36 -0
- package/src/lib/lib/atomix-table/atomix-table.component.css +152 -0
- package/src/lib/lib/atomix-table/atomix-table.component.html +647 -0
- package/src/lib/lib/atomix-table/atomix-table.component.spec.ts +1648 -0
- package/src/lib/lib/atomix-table/atomix-table.component.ts +422 -0
- package/src/lib/lib/atomix-table/atomix-table.models.ts +39 -0
- package/src/lib/lib/atomix-tag/atomix-tag.component.css +0 -0
- package/src/lib/lib/atomix-tag/atomix-tag.component.html +6 -0
- package/src/lib/lib/atomix-tag/atomix-tag.component.spec.ts +47 -0
- package/src/lib/lib/atomix-tag/atomix-tag.component.ts +13 -0
- package/src/lib/lib/utils/prime-icons.util.spec.ts +21 -0
- package/src/lib/lib/utils/prime-icons.util.ts +11 -0
- package/src/lib/primekit.component.spec.ts +19 -0
- package/src/lib/primekit.component.ts +10 -0
- package/src/lib/primekit.module.spec.ts +155 -0
- package/src/lib/primekit.module.ts +183 -0
- package/src/lib/primekit.service.spec.ts +17 -0
- package/src/lib/primekit.service.ts +8 -0
- package/{public-api.d.ts → src/public-api.ts} +47 -37
- package/tsconfig.lib.json +13 -0
- package/tsconfig.lib.prod.json +11 -0
- package/tsconfig.spec.json +10 -0
- package/esm2022/lib/lib/atomix-alert/atomix-alert.component.mjs +0 -76
- package/esm2022/lib/lib/atomix-autocomplete/atomix-autocomplete.component.mjs +0 -108
- package/esm2022/lib/lib/atomix-button/atomix-button.component.mjs +0 -49
- package/esm2022/lib/lib/atomix-button/atomix-button.models.mjs +0 -2
- package/esm2022/lib/lib/atomix-calendar/atomix-calendar.component.mjs +0 -90
- package/esm2022/lib/lib/atomix-card/atomix-card.component.mjs +0 -24
- package/esm2022/lib/lib/atomix-confirmation-dialog/atomix-confirmation-dialog.component.mjs +0 -28
- package/esm2022/lib/lib/atomix-daterange-calendar/atomix-daterange-calendar.component.mjs +0 -648
- package/esm2022/lib/lib/atomix-divider/atomix-divider.component.mjs +0 -27
- package/esm2022/lib/lib/atomix-dropdown/atomix-dropdown.component.mjs +0 -105
- package/esm2022/lib/lib/atomix-dynamic-dialog/atomix-dynamic-dialog.component.mjs +0 -38
- package/esm2022/lib/lib/atomix-dynamic-dialog/atomix-dynamic-dialog.models.mjs +0 -2
- package/esm2022/lib/lib/atomix-form/atomix-form-autocomplete/atomix-form-autocomplete.component.mjs +0 -67
- package/esm2022/lib/lib/atomix-form/atomix-form-calendar/atomix-form-calendar.component.mjs +0 -59
- package/esm2022/lib/lib/atomix-form/atomix-form-checkbox/atomix-form-checkbox.component.mjs +0 -48
- package/esm2022/lib/lib/atomix-form/atomix-form-chips/atomix-form-chips.component.mjs +0 -54
- package/esm2022/lib/lib/atomix-form/atomix-form-chips/form.chips.models.mjs +0 -2
- package/esm2022/lib/lib/atomix-form/atomix-form-dropdown/atomix-form-dropdown.component.mjs +0 -70
- package/esm2022/lib/lib/atomix-form/atomix-form-input-component/atomix-form-input-component.component.mjs +0 -80
- package/esm2022/lib/lib/atomix-form/atomix-form-inputmask-component/atomix-form-inputmask-component.component.mjs +0 -48
- package/esm2022/lib/lib/atomix-form/atomix-form-password-component/atomix-form-password-component.component.mjs +0 -48
- package/esm2022/lib/lib/atomix-form/atomix-form-radio-button/atomix-radio-button.component.mjs +0 -46
- package/esm2022/lib/lib/atomix-form/atomix-form-textarea/atomix-form-textarea.component.mjs +0 -46
- package/esm2022/lib/lib/atomix-input/atomix-input.component.mjs +0 -94
- package/esm2022/lib/lib/atomix-input-switch/atomix-input-switch.component.mjs +0 -85
- package/esm2022/lib/lib/atomix-messages/messages.component.mjs +0 -33
- package/esm2022/lib/lib/atomix-pagination/atomix-pagination.component.mjs +0 -48
- package/esm2022/lib/lib/atomix-radio-button/atomix-radio-button.component.mjs +0 -50
- package/esm2022/lib/lib/atomix-search-dropdown/atomix-search-dropdown.component.mjs +0 -149
- package/esm2022/lib/lib/atomix-select-button/atomix-select-button-models.mjs +0 -2
- package/esm2022/lib/lib/atomix-select-button/atomix-select-button.component.mjs +0 -25
- package/esm2022/lib/lib/atomix-snackbar/atomix-snackbar.component.mjs +0 -29
- package/esm2022/lib/lib/atomix-spinner/atomix-spinner.component.mjs +0 -24
- package/esm2022/lib/lib/atomix-steps/atomix-steps.component.mjs +0 -41
- package/esm2022/lib/lib/atomix-tabMenu/atomix-tabMenu.component.mjs +0 -51
- package/esm2022/lib/lib/atomix-table/atomix-table.component.mjs +0 -454
- package/esm2022/lib/lib/atomix-table/atomix-table.models.mjs +0 -2
- package/esm2022/lib/lib/atomix-tag/atomix-tag.component.mjs +0 -24
- package/esm2022/lib/lib/utils/prime-icons.util.mjs +0 -10
- package/esm2022/lib/primekit.component.mjs +0 -11
- package/esm2022/lib/primekit.module.mjs +0 -313
- package/esm2022/lib/primekit.service.mjs +0 -14
- package/esm2022/primekit.mjs +0 -5
- package/esm2022/public-api.mjs +0 -43
- package/fesm2022/primekit.mjs +0 -3041
- package/fesm2022/primekit.mjs.map +0 -1
- package/index.d.ts +0 -5
- package/lib/lib/atomix-alert/atomix-alert.component.d.ts +0 -22
- package/lib/lib/atomix-autocomplete/atomix-autocomplete.component.d.ts +0 -34
- package/lib/lib/atomix-button/atomix-button.component.d.ts +0 -19
- package/lib/lib/atomix-calendar/atomix-calendar.component.d.ts +0 -27
- package/lib/lib/atomix-card/atomix-card.component.d.ts +0 -9
- package/lib/lib/atomix-confirmation-dialog/atomix-confirmation-dialog.component.d.ts +0 -12
- package/lib/lib/atomix-daterange-calendar/atomix-daterange-calendar.component.d.ts +0 -72
- package/lib/lib/atomix-divider/atomix-divider.component.d.ts +0 -12
- package/lib/lib/atomix-dropdown/atomix-dropdown.component.d.ts +0 -50
- package/lib/lib/atomix-dynamic-dialog/atomix-dynamic-dialog.component.d.ts +0 -15
- package/lib/lib/atomix-dynamic-dialog/atomix-dynamic-dialog.models.d.ts +0 -11
- package/lib/lib/atomix-form/atomix-form-autocomplete/atomix-form-autocomplete.component.d.ts +0 -25
- package/lib/lib/atomix-form/atomix-form-calendar/atomix-form-calendar.component.d.ts +0 -23
- package/lib/lib/atomix-form/atomix-form-checkbox/atomix-form-checkbox.component.d.ts +0 -18
- package/lib/lib/atomix-form/atomix-form-chips/atomix-form-chips.component.d.ts +0 -19
- package/lib/lib/atomix-form/atomix-form-chips/form.chips.models.d.ts +0 -5
- package/lib/lib/atomix-form/atomix-form-dropdown/atomix-form-dropdown.component.d.ts +0 -25
- package/lib/lib/atomix-form/atomix-form-input-component/atomix-form-input-component.component.d.ts +0 -28
- package/lib/lib/atomix-form/atomix-form-inputmask-component/atomix-form-inputmask-component.component.d.ts +0 -17
- package/lib/lib/atomix-form/atomix-form-password-component/atomix-form-password-component.component.d.ts +0 -17
- package/lib/lib/atomix-form/atomix-form-radio-button/atomix-radio-button.component.d.ts +0 -19
- package/lib/lib/atomix-form/atomix-form-textarea/atomix-form-textarea.component.d.ts +0 -17
- package/lib/lib/atomix-input/atomix-input.component.d.ts +0 -29
- package/lib/lib/atomix-input-switch/atomix-input-switch.component.d.ts +0 -30
- package/lib/lib/atomix-messages/messages.component.d.ts +0 -13
- package/lib/lib/atomix-pagination/atomix-pagination.component.d.ts +0 -19
- package/lib/lib/atomix-radio-button/atomix-radio-button.component.d.ts +0 -15
- package/lib/lib/atomix-search-dropdown/atomix-search-dropdown.component.d.ts +0 -60
- package/lib/lib/atomix-select-button/atomix-select-button.component.d.ts +0 -12
- package/lib/lib/atomix-snackbar/atomix-snackbar.component.d.ts +0 -12
- package/lib/lib/atomix-spinner/atomix-spinner.component.d.ts +0 -9
- package/lib/lib/atomix-steps/atomix-steps.component.d.ts +0 -19
- package/lib/lib/atomix-tabMenu/atomix-tabMenu.component.d.ts +0 -19
- package/lib/lib/atomix-table/atomix-table.component.d.ts +0 -119
- package/lib/lib/atomix-table/atomix-table.models.d.ts +0 -43
- package/lib/lib/atomix-tag/atomix-tag.component.d.ts +0 -9
- package/lib/lib/utils/prime-icons.util.d.ts +0 -3
- package/lib/primekit.component.d.ts +0 -5
- package/lib/primekit.module.d.ts +0 -70
- package/lib/primekit.service.d.ts +0 -6
|
@@ -0,0 +1,1648 @@
|
|
|
1
|
+
import { ChangeDetectorRef, NO_ERRORS_SCHEMA } from '@angular/core';
|
|
2
|
+
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
|
3
|
+
import { ConfirmationService } from 'primeng/api';
|
|
4
|
+
import { DatePipe } from '@angular/common';
|
|
5
|
+
import { AtomixTableComponent } from './atomix-table.component';
|
|
6
|
+
import { Column, Row } from './atomix-table.models';
|
|
7
|
+
|
|
8
|
+
describe('AtomixTableComponent', () => {
|
|
9
|
+
let component: AtomixTableComponent;
|
|
10
|
+
let fixture: ComponentFixture<AtomixTableComponent>;
|
|
11
|
+
let mockConfirmationService: { confirm: jest.Mock };
|
|
12
|
+
let mockDatePipe: { transform: jest.Mock };
|
|
13
|
+
let mockCdr: { detectChanges: jest.Mock };
|
|
14
|
+
|
|
15
|
+
beforeEach(() => {
|
|
16
|
+
mockConfirmationService = { confirm: jest.fn() };
|
|
17
|
+
mockDatePipe = { transform: jest.fn() };
|
|
18
|
+
mockCdr = { detectChanges: jest.fn() };
|
|
19
|
+
|
|
20
|
+
TestBed.configureTestingModule({
|
|
21
|
+
declarations: [AtomixTableComponent],
|
|
22
|
+
providers: [
|
|
23
|
+
{ provide: ConfirmationService, useValue: mockConfirmationService },
|
|
24
|
+
{ provide: DatePipe, useValue: mockDatePipe },
|
|
25
|
+
{ provide: ChangeDetectorRef, useValue: mockCdr },
|
|
26
|
+
],
|
|
27
|
+
schemas: [NO_ERRORS_SCHEMA],
|
|
28
|
+
});
|
|
29
|
+
fixture = TestBed.createComponent(AtomixTableComponent);
|
|
30
|
+
component = fixture.componentInstance;
|
|
31
|
+
|
|
32
|
+
// Initialize required inputs to prevent template errors
|
|
33
|
+
component.rows = [];
|
|
34
|
+
component.cols = [];
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('should create', () => {
|
|
38
|
+
expect(component).toBeTruthy();
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
describe('initialization with rows and cols', () => {
|
|
42
|
+
it('should accept rows input', () => {
|
|
43
|
+
const mockRows: Row[] = [
|
|
44
|
+
{ id: '1', name: 'Item 1' },
|
|
45
|
+
{ id: '2', name: 'Item 2' },
|
|
46
|
+
];
|
|
47
|
+
component.rows = mockRows;
|
|
48
|
+
expect(component.rows).toEqual(mockRows);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('should accept cols input', () => {
|
|
52
|
+
const mockCols: Column[] = [
|
|
53
|
+
{ name: 'Name', field: 'name' },
|
|
54
|
+
{ name: 'Status', field: 'status', type: 'string' },
|
|
55
|
+
];
|
|
56
|
+
component.cols = mockCols;
|
|
57
|
+
expect(component.cols).toEqual(mockCols);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it('should accept rows as an array of data objects', () => {
|
|
61
|
+
const mockRows: Row[] = [
|
|
62
|
+
{ id: '1', name: 'Product A', price: 10.99 },
|
|
63
|
+
{ id: '2', name: 'Product B', price: 20.5 },
|
|
64
|
+
{ id: '3', name: 'Product C', price: 5.0 },
|
|
65
|
+
];
|
|
66
|
+
component.rows = mockRows;
|
|
67
|
+
expect(component.rows).toHaveLength(3);
|
|
68
|
+
expect(component.rows[0]).toEqual({ id: '1', name: 'Product A', price: 10.99 });
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it('should accept cols as an array of column definitions', () => {
|
|
72
|
+
const mockCols: Column[] = [
|
|
73
|
+
{ name: 'Product Name', field: 'name', type: 'string' },
|
|
74
|
+
{ name: 'Price', field: 'price', type: 'number' },
|
|
75
|
+
{ name: 'Created', field: 'createdAt', type: 'date', filterByDate: true },
|
|
76
|
+
];
|
|
77
|
+
component.cols = mockCols;
|
|
78
|
+
expect(component.cols).toHaveLength(3);
|
|
79
|
+
expect(component.cols[2]).toEqual({
|
|
80
|
+
name: 'Created',
|
|
81
|
+
field: 'createdAt',
|
|
82
|
+
type: 'date',
|
|
83
|
+
filterByDate: true,
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it('should initialize with both rows and cols together', () => {
|
|
88
|
+
const mockRows: Row[] = [
|
|
89
|
+
{ id: '1', name: 'Item 1', status: 'active' },
|
|
90
|
+
];
|
|
91
|
+
const mockCols: Column[] = [
|
|
92
|
+
{ name: 'Name', field: 'name' },
|
|
93
|
+
{ name: 'Status', field: 'status' },
|
|
94
|
+
];
|
|
95
|
+
component.rows = mockRows;
|
|
96
|
+
component.cols = mockCols;
|
|
97
|
+
expect(component.rows).toEqual(mockRows);
|
|
98
|
+
expect(component.cols).toEqual(mockCols);
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
describe('row selection', () => {
|
|
103
|
+
const mockRows: Row[] = [
|
|
104
|
+
{ id: '1', name: 'Item 1' },
|
|
105
|
+
{ id: '2', name: 'Item 2' },
|
|
106
|
+
{ id: '3', name: 'Item 3' },
|
|
107
|
+
];
|
|
108
|
+
|
|
109
|
+
beforeEach(() => {
|
|
110
|
+
component.rows = mockRows;
|
|
111
|
+
component.cols = [{ name: 'Name', field: 'name' }];
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
describe('onRowSelect', () => {
|
|
115
|
+
it('should emit selectedRows with the current selectedTableRows', () => {
|
|
116
|
+
const emitSpy = jest.spyOn(component.selectedRows, 'emit');
|
|
117
|
+
component.selectedTableRows = [mockRows[0]];
|
|
118
|
+
|
|
119
|
+
component.onRowSelect();
|
|
120
|
+
|
|
121
|
+
expect(emitSpy).toHaveBeenCalledWith([mockRows[0]]);
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it('should emit selectedRows with multiple selected rows', () => {
|
|
125
|
+
const emitSpy = jest.spyOn(component.selectedRows, 'emit');
|
|
126
|
+
component.selectedTableRows = [mockRows[0], mockRows[1]];
|
|
127
|
+
|
|
128
|
+
component.onRowSelect();
|
|
129
|
+
|
|
130
|
+
expect(emitSpy).toHaveBeenCalledWith([mockRows[0], mockRows[1]]);
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
it('should emit undefined when no rows are selected', () => {
|
|
134
|
+
const emitSpy = jest.spyOn(component.selectedRows, 'emit');
|
|
135
|
+
component.selectedTableRows = undefined;
|
|
136
|
+
|
|
137
|
+
component.onRowSelect();
|
|
138
|
+
|
|
139
|
+
expect(emitSpy).toHaveBeenCalledWith(undefined);
|
|
140
|
+
});
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
describe('onRowUnselect', () => {
|
|
144
|
+
it('should emit selectedRows after a row is unselected', () => {
|
|
145
|
+
const emitSpy = jest.spyOn(component.selectedRows, 'emit');
|
|
146
|
+
component.selectedTableRows = [mockRows[0], mockRows[1]];
|
|
147
|
+
|
|
148
|
+
// Simulate unselecting a row by removing it from selectedTableRows
|
|
149
|
+
component.selectedTableRows = [mockRows[0]];
|
|
150
|
+
component.onRowUnselect();
|
|
151
|
+
|
|
152
|
+
expect(emitSpy).toHaveBeenCalledWith([mockRows[0]]);
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
it('should emit empty array when all rows are unselected', () => {
|
|
156
|
+
const emitSpy = jest.spyOn(component.selectedRows, 'emit');
|
|
157
|
+
component.selectedTableRows = [];
|
|
158
|
+
|
|
159
|
+
component.onRowUnselect();
|
|
160
|
+
|
|
161
|
+
expect(emitSpy).toHaveBeenCalledWith([]);
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
it('should emit undefined when selectedTableRows is undefined', () => {
|
|
165
|
+
const emitSpy = jest.spyOn(component.selectedRows, 'emit');
|
|
166
|
+
component.selectedTableRows = undefined;
|
|
167
|
+
|
|
168
|
+
component.onRowUnselect();
|
|
169
|
+
|
|
170
|
+
expect(emitSpy).toHaveBeenCalledWith(undefined);
|
|
171
|
+
});
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
describe('onCheckboxSelect', () => {
|
|
175
|
+
it('should emit selectedRows with the current selectedTableRows', () => {
|
|
176
|
+
const emitSpy = jest.spyOn(component.selectedRows, 'emit');
|
|
177
|
+
component.selectedTableRows = [mockRows[0], mockRows[2]];
|
|
178
|
+
|
|
179
|
+
component.onCheckboxSelect();
|
|
180
|
+
|
|
181
|
+
expect(emitSpy).toHaveBeenCalledWith([mockRows[0], mockRows[2]]);
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
it('should emit all rows when all checkboxes are selected', () => {
|
|
185
|
+
const emitSpy = jest.spyOn(component.selectedRows, 'emit');
|
|
186
|
+
component.selectedTableRows = [...mockRows];
|
|
187
|
+
|
|
188
|
+
component.onCheckboxSelect();
|
|
189
|
+
|
|
190
|
+
expect(emitSpy).toHaveBeenCalledWith(mockRows);
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
it('should emit empty array when no checkboxes are selected', () => {
|
|
194
|
+
const emitSpy = jest.spyOn(component.selectedRows, 'emit');
|
|
195
|
+
component.selectedTableRows = [];
|
|
196
|
+
|
|
197
|
+
component.onCheckboxSelect();
|
|
198
|
+
|
|
199
|
+
expect(emitSpy).toHaveBeenCalledWith([]);
|
|
200
|
+
});
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
describe('selectedRows EventEmitter', () => {
|
|
204
|
+
it('should emit correct payload when subscribing to selectedRows output', () => {
|
|
205
|
+
const emittedValues: (Row[] | undefined)[] = [];
|
|
206
|
+
component.selectedRows.subscribe((value) => emittedValues.push(value));
|
|
207
|
+
|
|
208
|
+
component.selectedTableRows = [mockRows[0]];
|
|
209
|
+
component.onRowSelect();
|
|
210
|
+
|
|
211
|
+
component.selectedTableRows = [mockRows[0], mockRows[1]];
|
|
212
|
+
component.onCheckboxSelect();
|
|
213
|
+
|
|
214
|
+
component.selectedTableRows = [mockRows[1]];
|
|
215
|
+
component.onRowUnselect();
|
|
216
|
+
|
|
217
|
+
expect(emittedValues).toEqual([
|
|
218
|
+
[mockRows[0]],
|
|
219
|
+
[mockRows[0], mockRows[1]],
|
|
220
|
+
[mockRows[1]],
|
|
221
|
+
]);
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
it('should emit the selectedTableRows reference each time a selection method is called', () => {
|
|
225
|
+
const emitSpy = jest.spyOn(component.selectedRows, 'emit');
|
|
226
|
+
|
|
227
|
+
component.selectedTableRows = [mockRows[2]];
|
|
228
|
+
component.onRowSelect();
|
|
229
|
+
|
|
230
|
+
component.selectedTableRows = [mockRows[0], mockRows[1], mockRows[2]];
|
|
231
|
+
component.onCheckboxSelect();
|
|
232
|
+
|
|
233
|
+
expect(emitSpy).toHaveBeenCalledTimes(2);
|
|
234
|
+
expect(emitSpy).toHaveBeenNthCalledWith(1, [mockRows[2]]);
|
|
235
|
+
expect(emitSpy).toHaveBeenNthCalledWith(2, [mockRows[0], mockRows[1], mockRows[2]]);
|
|
236
|
+
});
|
|
237
|
+
});
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
describe('selectAllOnInit behavior', () => {
|
|
241
|
+
const mockRows: Row[] = [
|
|
242
|
+
{ id: '1', name: 'Item 1' },
|
|
243
|
+
{ id: '2', name: 'Item 2' },
|
|
244
|
+
{ id: '3', name: 'Item 3' },
|
|
245
|
+
];
|
|
246
|
+
|
|
247
|
+
it('should select all rows when enableSelectAllOnInit is true and rows are provided', () => {
|
|
248
|
+
component.enableSelectAllOnInit = true;
|
|
249
|
+
component.rows = mockRows;
|
|
250
|
+
|
|
251
|
+
component.ngOnChanges({});
|
|
252
|
+
|
|
253
|
+
expect(component.selectedTableRows).toEqual(mockRows);
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
it('should NOT auto-select rows when enableSelectAllOnInit is false', () => {
|
|
257
|
+
component.enableSelectAllOnInit = false;
|
|
258
|
+
component.rows = mockRows;
|
|
259
|
+
|
|
260
|
+
component.ngOnChanges({});
|
|
261
|
+
|
|
262
|
+
expect(component.selectedTableRows).toBeUndefined();
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
it('should not set selectedTableRows when enableSelectAllOnInit is true but rows is empty', () => {
|
|
266
|
+
component.enableSelectAllOnInit = true;
|
|
267
|
+
component.rows = [];
|
|
268
|
+
|
|
269
|
+
component.ngOnChanges({});
|
|
270
|
+
|
|
271
|
+
// onRowsInit returns early when rows.length === 0, so selectedTableRows stays as initialized
|
|
272
|
+
expect(component.selectedTableRows).toBeUndefined();
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
it('should emit selectedRows when selectAllOnInit triggers with rows', () => {
|
|
276
|
+
const emitSpy = jest.spyOn(component.selectedRows, 'emit');
|
|
277
|
+
component.enableSelectAllOnInit = true;
|
|
278
|
+
component.rows = mockRows;
|
|
279
|
+
|
|
280
|
+
component.ngOnChanges({});
|
|
281
|
+
|
|
282
|
+
expect(emitSpy).toHaveBeenCalledWith(mockRows);
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
it('should not emit selectedRows when rows is empty (early return)', () => {
|
|
286
|
+
const emitSpy = jest.spyOn(component.selectedRows, 'emit');
|
|
287
|
+
component.enableSelectAllOnInit = true;
|
|
288
|
+
component.rows = [];
|
|
289
|
+
|
|
290
|
+
component.ngOnChanges({});
|
|
291
|
+
|
|
292
|
+
expect(emitSpy).not.toHaveBeenCalled();
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
it('should emit undefined for selectedRows when enableSelectAllOnInit is false', () => {
|
|
296
|
+
const emitSpy = jest.spyOn(component.selectedRows, 'emit');
|
|
297
|
+
component.enableSelectAllOnInit = false;
|
|
298
|
+
component.rows = mockRows;
|
|
299
|
+
|
|
300
|
+
component.ngOnChanges({});
|
|
301
|
+
|
|
302
|
+
expect(emitSpy).toHaveBeenCalledWith(undefined);
|
|
303
|
+
});
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
describe('filtering', () => {
|
|
307
|
+
beforeEach(() => {
|
|
308
|
+
component.rows = [
|
|
309
|
+
{ id: '1', name: 'Item 1', status: 'active' },
|
|
310
|
+
{ id: '2', name: 'Item 2', status: 'inactive' },
|
|
311
|
+
];
|
|
312
|
+
component.cols = [
|
|
313
|
+
{ name: 'Name', field: 'name' },
|
|
314
|
+
{ name: 'Status', field: 'status' },
|
|
315
|
+
];
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
describe('filterResults with text filters', () => {
|
|
319
|
+
it('should emit filterChange with processed text filter values', () => {
|
|
320
|
+
const emitSpy = jest.spyOn(component.filterChange, 'emit');
|
|
321
|
+
|
|
322
|
+
const event = {
|
|
323
|
+
filters: {
|
|
324
|
+
name: [{ value: 'Item 1', matchMode: 'contains', operator: 'and' }],
|
|
325
|
+
},
|
|
326
|
+
};
|
|
327
|
+
|
|
328
|
+
component.filterResults(event);
|
|
329
|
+
|
|
330
|
+
expect(emitSpy).toHaveBeenCalledWith({
|
|
331
|
+
name: [{ value: 'Item 1', matchMode: 'contains', operator: 'and' }],
|
|
332
|
+
});
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
it('should exclude filters with null values', () => {
|
|
336
|
+
const emitSpy = jest.spyOn(component.filterChange, 'emit');
|
|
337
|
+
|
|
338
|
+
const event = {
|
|
339
|
+
filters: {
|
|
340
|
+
name: [{ value: null, matchMode: 'contains', operator: 'and' }],
|
|
341
|
+
status: [{ value: 'active', matchMode: 'equals', operator: 'and' }],
|
|
342
|
+
},
|
|
343
|
+
};
|
|
344
|
+
|
|
345
|
+
component.filterResults(event);
|
|
346
|
+
|
|
347
|
+
expect(emitSpy).toHaveBeenCalledWith({
|
|
348
|
+
status: [{ value: 'active', matchMode: 'equals', operator: 'and' }],
|
|
349
|
+
});
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
it('should emit empty object when all filter values are null', () => {
|
|
353
|
+
const emitSpy = jest.spyOn(component.filterChange, 'emit');
|
|
354
|
+
|
|
355
|
+
const event = {
|
|
356
|
+
filters: {
|
|
357
|
+
name: [{ value: null, matchMode: 'contains', operator: 'and' }],
|
|
358
|
+
status: [{ value: null, matchMode: 'equals', operator: 'and' }],
|
|
359
|
+
},
|
|
360
|
+
};
|
|
361
|
+
|
|
362
|
+
component.filterResults(event);
|
|
363
|
+
|
|
364
|
+
expect(emitSpy).toHaveBeenCalledWith({});
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
it('should handle multiple non-null filters for the same field', () => {
|
|
368
|
+
const emitSpy = jest.spyOn(component.filterChange, 'emit');
|
|
369
|
+
|
|
370
|
+
const event = {
|
|
371
|
+
filters: {
|
|
372
|
+
name: [
|
|
373
|
+
{ value: 'Item', matchMode: 'contains', operator: 'and' },
|
|
374
|
+
{ value: 'Product', matchMode: 'contains', operator: 'or' },
|
|
375
|
+
],
|
|
376
|
+
},
|
|
377
|
+
};
|
|
378
|
+
|
|
379
|
+
component.filterResults(event);
|
|
380
|
+
|
|
381
|
+
expect(emitSpy).toHaveBeenCalledWith({
|
|
382
|
+
name: [
|
|
383
|
+
{ value: 'Item', matchMode: 'contains', operator: 'and' },
|
|
384
|
+
{ value: 'Product', matchMode: 'contains', operator: 'or' },
|
|
385
|
+
],
|
|
386
|
+
});
|
|
387
|
+
});
|
|
388
|
+
|
|
389
|
+
it('should normalize dateIs matchMode to equals', () => {
|
|
390
|
+
const emitSpy = jest.spyOn(component.filterChange, 'emit');
|
|
391
|
+
|
|
392
|
+
const event = {
|
|
393
|
+
filters: {
|
|
394
|
+
createdAt: [{ value: '2024-01-15', matchMode: 'dateIs', operator: 'and' }],
|
|
395
|
+
},
|
|
396
|
+
};
|
|
397
|
+
|
|
398
|
+
component.filterResults(event);
|
|
399
|
+
|
|
400
|
+
expect(emitSpy).toHaveBeenCalledWith({
|
|
401
|
+
createdAt: [{ value: '2024-01-15', matchMode: 'equals', operator: 'and' }],
|
|
402
|
+
});
|
|
403
|
+
});
|
|
404
|
+
});
|
|
405
|
+
|
|
406
|
+
describe('filterResults with date filters', () => {
|
|
407
|
+
it('should format Date objects using DatePipe and set matchMode to equals', () => {
|
|
408
|
+
const emitSpy = jest.spyOn(component.filterChange, 'emit');
|
|
409
|
+
const testDate = new Date(2024, 0, 15); // Jan 15, 2024
|
|
410
|
+
mockDatePipe.transform.mockReturnValue('2024-01-15');
|
|
411
|
+
|
|
412
|
+
const event = {
|
|
413
|
+
filters: {
|
|
414
|
+
createdAt: [{ value: testDate, matchMode: 'dateIs', operator: 'and' }],
|
|
415
|
+
},
|
|
416
|
+
};
|
|
417
|
+
|
|
418
|
+
component.filterResults(event);
|
|
419
|
+
|
|
420
|
+
expect(mockDatePipe.transform).toHaveBeenCalledWith(testDate, 'yyyy-MM-dd');
|
|
421
|
+
expect(emitSpy).toHaveBeenCalledWith({
|
|
422
|
+
createdAt: [{ value: '2024-01-15', matchMode: 'equals', operator: 'and' }],
|
|
423
|
+
});
|
|
424
|
+
});
|
|
425
|
+
|
|
426
|
+
it('should handle multiple date filters across different fields', () => {
|
|
427
|
+
const emitSpy = jest.spyOn(component.filterChange, 'emit');
|
|
428
|
+
const date1 = new Date(2024, 0, 10);
|
|
429
|
+
const date2 = new Date(2024, 5, 20);
|
|
430
|
+
mockDatePipe.transform.mockImplementation((date: Date) => {
|
|
431
|
+
if (date === date1) return '2024-01-10';
|
|
432
|
+
if (date === date2) return '2024-06-20';
|
|
433
|
+
return '';
|
|
434
|
+
});
|
|
435
|
+
|
|
436
|
+
const event = {
|
|
437
|
+
filters: {
|
|
438
|
+
createdAt: [{ value: date1, matchMode: 'dateIs', operator: 'and' }],
|
|
439
|
+
updatedAt: [{ value: date2, matchMode: 'dateIs', operator: 'and' }],
|
|
440
|
+
},
|
|
441
|
+
};
|
|
442
|
+
|
|
443
|
+
component.filterResults(event);
|
|
444
|
+
|
|
445
|
+
expect(emitSpy).toHaveBeenCalledWith({
|
|
446
|
+
createdAt: [{ value: '2024-01-10', matchMode: 'equals', operator: 'and' }],
|
|
447
|
+
updatedAt: [{ value: '2024-06-20', matchMode: 'equals', operator: 'and' }],
|
|
448
|
+
});
|
|
449
|
+
});
|
|
450
|
+
});
|
|
451
|
+
|
|
452
|
+
describe('filterResults with date range filters', () => {
|
|
453
|
+
it('should format date range arrays using DatePipe and set matchMode to between', () => {
|
|
454
|
+
const emitSpy = jest.spyOn(component.filterChange, 'emit');
|
|
455
|
+
const startDate = new Date(2024, 0, 1);
|
|
456
|
+
const endDate = new Date(2024, 0, 31);
|
|
457
|
+
mockDatePipe.transform.mockImplementation((date: Date) => {
|
|
458
|
+
if (date === startDate) return '2024-01-01';
|
|
459
|
+
if (date === endDate) return '2024-01-31';
|
|
460
|
+
return '';
|
|
461
|
+
});
|
|
462
|
+
|
|
463
|
+
const event = {
|
|
464
|
+
filters: {
|
|
465
|
+
createdAt: [{ value: [startDate, endDate], matchMode: 'dateIs', operator: 'and' }],
|
|
466
|
+
},
|
|
467
|
+
};
|
|
468
|
+
|
|
469
|
+
component.filterResults(event);
|
|
470
|
+
|
|
471
|
+
expect(mockDatePipe.transform).toHaveBeenCalledWith(startDate, 'yyyy-MM-dd');
|
|
472
|
+
expect(mockDatePipe.transform).toHaveBeenCalledWith(endDate, 'yyyy-MM-dd');
|
|
473
|
+
expect(emitSpy).toHaveBeenCalledWith({
|
|
474
|
+
createdAt: [{ value: ['2024-01-01', '2024-01-31'], matchMode: 'between', operator: 'and' }],
|
|
475
|
+
});
|
|
476
|
+
});
|
|
477
|
+
|
|
478
|
+
it('should not treat arrays of non-Date values as date ranges', () => {
|
|
479
|
+
const emitSpy = jest.spyOn(component.filterChange, 'emit');
|
|
480
|
+
|
|
481
|
+
const event = {
|
|
482
|
+
filters: {
|
|
483
|
+
tags: [{ value: ['tag1', 'tag2'], matchMode: 'in', operator: 'and' }],
|
|
484
|
+
},
|
|
485
|
+
};
|
|
486
|
+
|
|
487
|
+
component.filterResults(event);
|
|
488
|
+
|
|
489
|
+
expect(emitSpy).toHaveBeenCalledWith({
|
|
490
|
+
tags: [{ value: ['tag1', 'tag2'], matchMode: 'in', operator: 'and' }],
|
|
491
|
+
});
|
|
492
|
+
});
|
|
493
|
+
});
|
|
494
|
+
|
|
495
|
+
describe('clearFilters', () => {
|
|
496
|
+
it('should call dt1.clear() and emit empty object via filterChange', () => {
|
|
497
|
+
const emitSpy = jest.spyOn(component.filterChange, 'emit');
|
|
498
|
+
const mockDt1 = { clear: jest.fn() };
|
|
499
|
+
(component as any).dt1 = mockDt1;
|
|
500
|
+
|
|
501
|
+
component.clearFilters();
|
|
502
|
+
|
|
503
|
+
expect(mockDt1.clear).toHaveBeenCalled();
|
|
504
|
+
expect(emitSpy).toHaveBeenCalledWith({});
|
|
505
|
+
});
|
|
506
|
+
|
|
507
|
+
it('should not emit or throw when dt1 is undefined', () => {
|
|
508
|
+
const emitSpy = jest.spyOn(component.filterChange, 'emit');
|
|
509
|
+
(component as any).dt1 = undefined;
|
|
510
|
+
|
|
511
|
+
expect(() => component.clearFilters()).not.toThrow();
|
|
512
|
+
expect(emitSpy).not.toHaveBeenCalled();
|
|
513
|
+
});
|
|
514
|
+
});
|
|
515
|
+
});
|
|
516
|
+
|
|
517
|
+
describe('pagination', () => {
|
|
518
|
+
beforeEach(() => {
|
|
519
|
+
component.rows = [
|
|
520
|
+
{ id: '1', name: 'Item 1' },
|
|
521
|
+
{ id: '2', name: 'Item 2' },
|
|
522
|
+
];
|
|
523
|
+
component.cols = [{ name: 'Name', field: 'name' }];
|
|
524
|
+
});
|
|
525
|
+
|
|
526
|
+
describe('onPage', () => {
|
|
527
|
+
it('should calculate page 0 when event.first is 0', () => {
|
|
528
|
+
const emitSpy = jest.spyOn(component.pageChange, 'emit');
|
|
529
|
+
|
|
530
|
+
component.onPage({ first: 0, rows: 10 } as any);
|
|
531
|
+
|
|
532
|
+
expect(emitSpy).toHaveBeenCalledWith({ page: 0, size: 10 });
|
|
533
|
+
});
|
|
534
|
+
|
|
535
|
+
it('should calculate page 1 when first equals rows (second page)', () => {
|
|
536
|
+
const emitSpy = jest.spyOn(component.pageChange, 'emit');
|
|
537
|
+
|
|
538
|
+
component.onPage({ first: 10, rows: 10 } as any);
|
|
539
|
+
|
|
540
|
+
expect(emitSpy).toHaveBeenCalledWith({ page: 1, size: 10 });
|
|
541
|
+
});
|
|
542
|
+
|
|
543
|
+
it('should calculate page 2 when first is twice the rows', () => {
|
|
544
|
+
const emitSpy = jest.spyOn(component.pageChange, 'emit');
|
|
545
|
+
|
|
546
|
+
component.onPage({ first: 50, rows: 25 } as any);
|
|
547
|
+
|
|
548
|
+
expect(emitSpy).toHaveBeenCalledWith({ page: 2, size: 25 });
|
|
549
|
+
});
|
|
550
|
+
|
|
551
|
+
it('should calculate page 3 when first is 75 and rows is 25', () => {
|
|
552
|
+
const emitSpy = jest.spyOn(component.pageChange, 'emit');
|
|
553
|
+
|
|
554
|
+
component.onPage({ first: 75, rows: 25 } as any);
|
|
555
|
+
|
|
556
|
+
expect(emitSpy).toHaveBeenCalledWith({ page: 3, size: 25 });
|
|
557
|
+
});
|
|
558
|
+
|
|
559
|
+
it('should pass the correct size from event.rows with page size 50', () => {
|
|
560
|
+
const emitSpy = jest.spyOn(component.pageChange, 'emit');
|
|
561
|
+
|
|
562
|
+
component.onPage({ first: 100, rows: 50 } as any);
|
|
563
|
+
|
|
564
|
+
expect(emitSpy).toHaveBeenCalledWith({ page: 2, size: 50 });
|
|
565
|
+
});
|
|
566
|
+
|
|
567
|
+
it('should handle page size of 100', () => {
|
|
568
|
+
const emitSpy = jest.spyOn(component.pageChange, 'emit');
|
|
569
|
+
|
|
570
|
+
component.onPage({ first: 300, rows: 100 } as any);
|
|
571
|
+
|
|
572
|
+
expect(emitSpy).toHaveBeenCalledWith({ page: 3, size: 100 });
|
|
573
|
+
});
|
|
574
|
+
});
|
|
575
|
+
|
|
576
|
+
describe('pageChange EventEmitter', () => {
|
|
577
|
+
it('should emit correct page and size values when subscribing to pageChange', () => {
|
|
578
|
+
const emittedValues: { page: number; size: number }[] = [];
|
|
579
|
+
component.pageChange.subscribe((value) => emittedValues.push(value));
|
|
580
|
+
|
|
581
|
+
component.onPage({ first: 0, rows: 25 } as any);
|
|
582
|
+
component.onPage({ first: 25, rows: 25 } as any);
|
|
583
|
+
component.onPage({ first: 50, rows: 25 } as any);
|
|
584
|
+
|
|
585
|
+
expect(emittedValues).toEqual([
|
|
586
|
+
{ page: 0, size: 25 },
|
|
587
|
+
{ page: 1, size: 25 },
|
|
588
|
+
{ page: 2, size: 25 },
|
|
589
|
+
]);
|
|
590
|
+
});
|
|
591
|
+
|
|
592
|
+
it('should emit updated size when page size changes', () => {
|
|
593
|
+
const emittedValues: { page: number; size: number }[] = [];
|
|
594
|
+
component.pageChange.subscribe((value) => emittedValues.push(value));
|
|
595
|
+
|
|
596
|
+
component.onPage({ first: 0, rows: 10 } as any);
|
|
597
|
+
component.onPage({ first: 0, rows: 50 } as any);
|
|
598
|
+
|
|
599
|
+
expect(emittedValues).toEqual([
|
|
600
|
+
{ page: 0, size: 10 },
|
|
601
|
+
{ page: 0, size: 50 },
|
|
602
|
+
]);
|
|
603
|
+
});
|
|
604
|
+
|
|
605
|
+
it('should emit page 0 with size 500 for large page sizes', () => {
|
|
606
|
+
const emitSpy = jest.spyOn(component.pageChange, 'emit');
|
|
607
|
+
|
|
608
|
+
component.onPage({ first: 500, rows: 500 } as any);
|
|
609
|
+
|
|
610
|
+
expect(emitSpy).toHaveBeenCalledWith({ page: 1, size: 500 });
|
|
611
|
+
});
|
|
612
|
+
});
|
|
613
|
+
});
|
|
614
|
+
|
|
615
|
+
describe('sorting', () => {
|
|
616
|
+
beforeEach(() => {
|
|
617
|
+
component.rows = [
|
|
618
|
+
{ id: '1', name: 'Banana', status: 'active' },
|
|
619
|
+
{ id: '2', name: 'Apple', status: 'inactive' },
|
|
620
|
+
];
|
|
621
|
+
component.cols = [
|
|
622
|
+
{ name: 'Name', field: 'name' },
|
|
623
|
+
{ name: 'Status', field: 'status' },
|
|
624
|
+
];
|
|
625
|
+
component.sortBy = '';
|
|
626
|
+
component.orderBy = '';
|
|
627
|
+
});
|
|
628
|
+
|
|
629
|
+
describe('customSort direction cycling', () => {
|
|
630
|
+
it('should set direction to asc on first call for a column', () => {
|
|
631
|
+
const emitSpy = jest.spyOn(component.sortHandler, 'emit');
|
|
632
|
+
|
|
633
|
+
component.customSort('name');
|
|
634
|
+
|
|
635
|
+
expect(component.sortBy).toBe('name');
|
|
636
|
+
expect(component.orderBy).toBe('asc');
|
|
637
|
+
expect(emitSpy).toHaveBeenCalledWith({ columnName: 'name', direction: 'asc' });
|
|
638
|
+
});
|
|
639
|
+
|
|
640
|
+
it('should set direction to desc on second call for the same column', () => {
|
|
641
|
+
component.customSort('name'); // first call -> asc
|
|
642
|
+
|
|
643
|
+
const emitSpy = jest.spyOn(component.sortHandler, 'emit');
|
|
644
|
+
component.customSort('name'); // second call -> desc
|
|
645
|
+
|
|
646
|
+
expect(component.sortBy).toBe('name');
|
|
647
|
+
expect(component.orderBy).toBe('desc');
|
|
648
|
+
expect(emitSpy).toHaveBeenCalledWith({ columnName: 'name', direction: 'desc' });
|
|
649
|
+
});
|
|
650
|
+
|
|
651
|
+
it('should clear direction on third call for the same column', () => {
|
|
652
|
+
component.customSort('name'); // first call -> asc
|
|
653
|
+
component.customSort('name'); // second call -> desc
|
|
654
|
+
|
|
655
|
+
const emitSpy = jest.spyOn(component.sortHandler, 'emit');
|
|
656
|
+
component.customSort('name'); // third call -> clear
|
|
657
|
+
|
|
658
|
+
expect(component.sortBy).toBe('name');
|
|
659
|
+
expect(component.orderBy).toBe('');
|
|
660
|
+
expect(emitSpy).toHaveBeenCalledWith({ columnName: 'name', direction: '' });
|
|
661
|
+
});
|
|
662
|
+
|
|
663
|
+
it('should cycle back to asc after clearing', () => {
|
|
664
|
+
component.customSort('name'); // asc
|
|
665
|
+
component.customSort('name'); // desc
|
|
666
|
+
component.customSort('name'); // clear
|
|
667
|
+
|
|
668
|
+
const emitSpy = jest.spyOn(component.sortHandler, 'emit');
|
|
669
|
+
component.customSort('name'); // back to asc
|
|
670
|
+
|
|
671
|
+
expect(component.sortBy).toBe('name');
|
|
672
|
+
expect(component.orderBy).toBe('asc');
|
|
673
|
+
expect(emitSpy).toHaveBeenCalledWith({ columnName: 'name', direction: 'asc' });
|
|
674
|
+
});
|
|
675
|
+
});
|
|
676
|
+
|
|
677
|
+
describe('sortHandler emission', () => {
|
|
678
|
+
it('should emit sortHandler with columnName and direction', () => {
|
|
679
|
+
const emitSpy = jest.spyOn(component.sortHandler, 'emit');
|
|
680
|
+
|
|
681
|
+
component.customSort('status');
|
|
682
|
+
|
|
683
|
+
expect(emitSpy).toHaveBeenCalledTimes(1);
|
|
684
|
+
expect(emitSpy).toHaveBeenCalledWith({ columnName: 'status', direction: 'asc' });
|
|
685
|
+
});
|
|
686
|
+
|
|
687
|
+
it('should emit on every call to customSort', () => {
|
|
688
|
+
const emittedValues: any[] = [];
|
|
689
|
+
component.sortHandler.subscribe((value: any) => emittedValues.push(value));
|
|
690
|
+
|
|
691
|
+
component.customSort('name');
|
|
692
|
+
component.customSort('name');
|
|
693
|
+
component.customSort('name');
|
|
694
|
+
|
|
695
|
+
expect(emittedValues).toEqual([
|
|
696
|
+
{ columnName: 'name', direction: 'asc' },
|
|
697
|
+
{ columnName: 'name', direction: 'desc' },
|
|
698
|
+
{ columnName: 'name', direction: '' },
|
|
699
|
+
]);
|
|
700
|
+
});
|
|
701
|
+
});
|
|
702
|
+
|
|
703
|
+
describe('sorting different columns', () => {
|
|
704
|
+
it('should reset direction to asc when switching to a different column', () => {
|
|
705
|
+
component.customSort('name'); // name -> asc
|
|
706
|
+
component.customSort('name'); // name -> desc
|
|
707
|
+
|
|
708
|
+
const emitSpy = jest.spyOn(component.sortHandler, 'emit');
|
|
709
|
+
component.customSort('status'); // switch to status -> asc
|
|
710
|
+
|
|
711
|
+
expect(component.sortBy).toBe('status');
|
|
712
|
+
expect(component.orderBy).toBe('asc');
|
|
713
|
+
expect(emitSpy).toHaveBeenCalledWith({ columnName: 'status', direction: 'asc' });
|
|
714
|
+
});
|
|
715
|
+
|
|
716
|
+
it('should start fresh cycling on the new column after switching', () => {
|
|
717
|
+
component.customSort('name'); // name -> asc
|
|
718
|
+
component.customSort('status'); // status -> asc (new column)
|
|
719
|
+
|
|
720
|
+
const emitSpy = jest.spyOn(component.sortHandler, 'emit');
|
|
721
|
+
component.customSort('status'); // status -> desc
|
|
722
|
+
|
|
723
|
+
expect(component.sortBy).toBe('status');
|
|
724
|
+
expect(component.orderBy).toBe('desc');
|
|
725
|
+
expect(emitSpy).toHaveBeenCalledWith({ columnName: 'status', direction: 'desc' });
|
|
726
|
+
});
|
|
727
|
+
|
|
728
|
+
it('should reset to asc when switching columns even after clearing', () => {
|
|
729
|
+
component.customSort('name'); // name -> asc
|
|
730
|
+
component.customSort('name'); // name -> desc
|
|
731
|
+
component.customSort('name'); // name -> clear
|
|
732
|
+
|
|
733
|
+
const emitSpy = jest.spyOn(component.sortHandler, 'emit');
|
|
734
|
+
component.customSort('status'); // switch to status -> asc
|
|
735
|
+
|
|
736
|
+
expect(component.sortBy).toBe('status');
|
|
737
|
+
expect(component.orderBy).toBe('asc');
|
|
738
|
+
expect(emitSpy).toHaveBeenCalledWith({ columnName: 'status', direction: 'asc' });
|
|
739
|
+
});
|
|
740
|
+
});
|
|
741
|
+
});
|
|
742
|
+
|
|
743
|
+
describe('row reorder', () => {
|
|
744
|
+
const mockRows: Row[] = [
|
|
745
|
+
{ id: '1', name: 'Item 1' },
|
|
746
|
+
{ id: '2', name: 'Item 2' },
|
|
747
|
+
{ id: '3', name: 'Item 3' },
|
|
748
|
+
{ id: '4', name: 'Item 4' },
|
|
749
|
+
];
|
|
750
|
+
|
|
751
|
+
beforeEach(() => {
|
|
752
|
+
component.rows = mockRows;
|
|
753
|
+
component.cols = [{ name: 'Name', field: 'name' }];
|
|
754
|
+
});
|
|
755
|
+
|
|
756
|
+
describe('onRowReorder', () => {
|
|
757
|
+
it('should emit rowReordered with previousIndex and currentIndex from the event', () => {
|
|
758
|
+
const emitSpy = jest.spyOn(component.rowReordered, 'emit');
|
|
759
|
+
|
|
760
|
+
component.onRowReorder({ dragIndex: 0, dropIndex: 2 } as any);
|
|
761
|
+
|
|
762
|
+
expect(emitSpy).toHaveBeenCalledWith({ previousIndex: 0, currentIndex: 2 });
|
|
763
|
+
});
|
|
764
|
+
|
|
765
|
+
it('should emit rowReordered when moving a row down', () => {
|
|
766
|
+
const emitSpy = jest.spyOn(component.rowReordered, 'emit');
|
|
767
|
+
|
|
768
|
+
component.onRowReorder({ dragIndex: 1, dropIndex: 3 } as any);
|
|
769
|
+
|
|
770
|
+
expect(emitSpy).toHaveBeenCalledWith({ previousIndex: 1, currentIndex: 3 });
|
|
771
|
+
});
|
|
772
|
+
|
|
773
|
+
it('should emit rowReordered when moving a row up', () => {
|
|
774
|
+
const emitSpy = jest.spyOn(component.rowReordered, 'emit');
|
|
775
|
+
|
|
776
|
+
component.onRowReorder({ dragIndex: 3, dropIndex: 0 } as any);
|
|
777
|
+
|
|
778
|
+
expect(emitSpy).toHaveBeenCalledWith({ previousIndex: 3, currentIndex: 0 });
|
|
779
|
+
});
|
|
780
|
+
|
|
781
|
+
it('should emit rowReordered when drag and drop indices are the same', () => {
|
|
782
|
+
const emitSpy = jest.spyOn(component.rowReordered, 'emit');
|
|
783
|
+
|
|
784
|
+
component.onRowReorder({ dragIndex: 2, dropIndex: 2 } as any);
|
|
785
|
+
|
|
786
|
+
expect(emitSpy).toHaveBeenCalledWith({ previousIndex: 2, currentIndex: 2 });
|
|
787
|
+
});
|
|
788
|
+
|
|
789
|
+
it('should emit rowReordered when moving from first to last position', () => {
|
|
790
|
+
const emitSpy = jest.spyOn(component.rowReordered, 'emit');
|
|
791
|
+
|
|
792
|
+
component.onRowReorder({ dragIndex: 0, dropIndex: 3 } as any);
|
|
793
|
+
|
|
794
|
+
expect(emitSpy).toHaveBeenCalledWith({ previousIndex: 0, currentIndex: 3 });
|
|
795
|
+
});
|
|
796
|
+
|
|
797
|
+
it('should emit rowReordered when moving from last to first position', () => {
|
|
798
|
+
const emitSpy = jest.spyOn(component.rowReordered, 'emit');
|
|
799
|
+
|
|
800
|
+
component.onRowReorder({ dragIndex: 3, dropIndex: 0 } as any);
|
|
801
|
+
|
|
802
|
+
expect(emitSpy).toHaveBeenCalledWith({ previousIndex: 3, currentIndex: 0 });
|
|
803
|
+
});
|
|
804
|
+
});
|
|
805
|
+
|
|
806
|
+
describe('rowReordered EventEmitter', () => {
|
|
807
|
+
it('should emit correct payload when subscribing to rowReordered output', () => {
|
|
808
|
+
const emittedValues: { previousIndex: number; currentIndex: number }[] = [];
|
|
809
|
+
component.rowReordered.subscribe((value) => emittedValues.push(value));
|
|
810
|
+
|
|
811
|
+
component.onRowReorder({ dragIndex: 0, dropIndex: 2 } as any);
|
|
812
|
+
component.onRowReorder({ dragIndex: 3, dropIndex: 1 } as any);
|
|
813
|
+
|
|
814
|
+
expect(emittedValues).toEqual([
|
|
815
|
+
{ previousIndex: 0, currentIndex: 2 },
|
|
816
|
+
{ previousIndex: 3, currentIndex: 1 },
|
|
817
|
+
]);
|
|
818
|
+
});
|
|
819
|
+
|
|
820
|
+
it('should emit once per onRowReorder call', () => {
|
|
821
|
+
const emitSpy = jest.spyOn(component.rowReordered, 'emit');
|
|
822
|
+
|
|
823
|
+
component.onRowReorder({ dragIndex: 1, dropIndex: 2 } as any);
|
|
824
|
+
|
|
825
|
+
expect(emitSpy).toHaveBeenCalledTimes(1);
|
|
826
|
+
});
|
|
827
|
+
});
|
|
828
|
+
});
|
|
829
|
+
|
|
830
|
+
describe('delete/action confirmations', () => {
|
|
831
|
+
const mockRowData: Row = { id: '1', name: 'Item 1', status: 'active' };
|
|
832
|
+
|
|
833
|
+
beforeEach(() => {
|
|
834
|
+
component.rows = [mockRowData];
|
|
835
|
+
component.cols = [{ name: 'Name', field: 'name' }];
|
|
836
|
+
});
|
|
837
|
+
|
|
838
|
+
describe('deleteRowConfirmation', () => {
|
|
839
|
+
it('should call ConfirmationService.confirm with correct message', () => {
|
|
840
|
+
component.deleteRowConfirmation(mockRowData);
|
|
841
|
+
|
|
842
|
+
expect(mockConfirmationService.confirm).toHaveBeenCalledTimes(1);
|
|
843
|
+
expect(mockConfirmationService.confirm).toHaveBeenCalledWith(
|
|
844
|
+
expect.objectContaining({ message: 'Delete this item?' })
|
|
845
|
+
);
|
|
846
|
+
});
|
|
847
|
+
|
|
848
|
+
it('should emit deleteRow when the confirmation is accepted', () => {
|
|
849
|
+
const emitSpy = jest.spyOn(component.deleteRow, 'emit');
|
|
850
|
+
|
|
851
|
+
mockConfirmationService.confirm.mockImplementation((config: any) => {
|
|
852
|
+
config.accept();
|
|
853
|
+
});
|
|
854
|
+
|
|
855
|
+
component.deleteRowConfirmation(mockRowData);
|
|
856
|
+
|
|
857
|
+
expect(emitSpy).toHaveBeenCalledWith(mockRowData);
|
|
858
|
+
});
|
|
859
|
+
|
|
860
|
+
it('should not emit deleteRow if accept is not called', () => {
|
|
861
|
+
const emitSpy = jest.spyOn(component.deleteRow, 'emit');
|
|
862
|
+
|
|
863
|
+
mockConfirmationService.confirm.mockImplementation(() => {
|
|
864
|
+
// Simulate user dismissing the dialog without accepting
|
|
865
|
+
});
|
|
866
|
+
|
|
867
|
+
component.deleteRowConfirmation(mockRowData);
|
|
868
|
+
|
|
869
|
+
expect(emitSpy).not.toHaveBeenCalled();
|
|
870
|
+
});
|
|
871
|
+
|
|
872
|
+
it('should pass the rowData to deleteRow emit on acceptance', () => {
|
|
873
|
+
const emitSpy = jest.spyOn(component.deleteRow, 'emit');
|
|
874
|
+
const specificRow: Row = { id: '99', name: 'Special Item', price: 42 };
|
|
875
|
+
|
|
876
|
+
mockConfirmationService.confirm.mockImplementation((config: any) => {
|
|
877
|
+
config.accept();
|
|
878
|
+
});
|
|
879
|
+
|
|
880
|
+
component.deleteRowConfirmation(specificRow);
|
|
881
|
+
|
|
882
|
+
expect(emitSpy).toHaveBeenCalledWith(specificRow);
|
|
883
|
+
});
|
|
884
|
+
});
|
|
885
|
+
|
|
886
|
+
describe('actionRowConfirmation with confirmation flag', () => {
|
|
887
|
+
beforeEach(() => {
|
|
888
|
+
component.actionButtonConfig = {
|
|
889
|
+
enabled: true,
|
|
890
|
+
icon: 'pi pi-check',
|
|
891
|
+
message: 'Are you sure you want to perform this action?',
|
|
892
|
+
confirmation: true,
|
|
893
|
+
class: 'p-button-rounded p-button-help',
|
|
894
|
+
};
|
|
895
|
+
});
|
|
896
|
+
|
|
897
|
+
it('should call ConfirmationService.confirm when confirmation is true', () => {
|
|
898
|
+
component.actionRowConfirmation(mockRowData);
|
|
899
|
+
|
|
900
|
+
expect(mockConfirmationService.confirm).toHaveBeenCalledTimes(1);
|
|
901
|
+
expect(mockConfirmationService.confirm).toHaveBeenCalledWith(
|
|
902
|
+
expect.objectContaining({
|
|
903
|
+
message: 'Are you sure you want to perform this action?',
|
|
904
|
+
})
|
|
905
|
+
);
|
|
906
|
+
});
|
|
907
|
+
|
|
908
|
+
it('should emit actionButton when the confirmation is accepted', () => {
|
|
909
|
+
const emitSpy = jest.spyOn(component.actionButton, 'emit');
|
|
910
|
+
|
|
911
|
+
mockConfirmationService.confirm.mockImplementation((config: any) => {
|
|
912
|
+
config.accept();
|
|
913
|
+
});
|
|
914
|
+
|
|
915
|
+
component.actionRowConfirmation(mockRowData);
|
|
916
|
+
|
|
917
|
+
expect(emitSpy).toHaveBeenCalledWith(mockRowData);
|
|
918
|
+
});
|
|
919
|
+
|
|
920
|
+
it('should not emit actionButton if accept is not called', () => {
|
|
921
|
+
const emitSpy = jest.spyOn(component.actionButton, 'emit');
|
|
922
|
+
|
|
923
|
+
mockConfirmationService.confirm.mockImplementation(() => {
|
|
924
|
+
// User dismisses without accepting
|
|
925
|
+
});
|
|
926
|
+
|
|
927
|
+
component.actionRowConfirmation(mockRowData);
|
|
928
|
+
|
|
929
|
+
expect(emitSpy).not.toHaveBeenCalled();
|
|
930
|
+
});
|
|
931
|
+
|
|
932
|
+
it('should use the actionButtonConfig.message in the confirmation dialog', () => {
|
|
933
|
+
component.actionButtonConfig.message = 'Custom confirmation message';
|
|
934
|
+
|
|
935
|
+
component.actionRowConfirmation(mockRowData);
|
|
936
|
+
|
|
937
|
+
expect(mockConfirmationService.confirm).toHaveBeenCalledWith(
|
|
938
|
+
expect.objectContaining({ message: 'Custom confirmation message' })
|
|
939
|
+
);
|
|
940
|
+
});
|
|
941
|
+
});
|
|
942
|
+
|
|
943
|
+
describe('actionRowConfirmation without confirmation flag', () => {
|
|
944
|
+
beforeEach(() => {
|
|
945
|
+
component.actionButtonConfig = {
|
|
946
|
+
enabled: true,
|
|
947
|
+
icon: 'pi pi-check',
|
|
948
|
+
message: '',
|
|
949
|
+
confirmation: false,
|
|
950
|
+
class: 'p-button-rounded p-button-help',
|
|
951
|
+
};
|
|
952
|
+
});
|
|
953
|
+
|
|
954
|
+
it('should emit actionButton directly without calling ConfirmationService', () => {
|
|
955
|
+
const emitSpy = jest.spyOn(component.actionButton, 'emit');
|
|
956
|
+
|
|
957
|
+
component.actionRowConfirmation(mockRowData);
|
|
958
|
+
|
|
959
|
+
expect(mockConfirmationService.confirm).not.toHaveBeenCalled();
|
|
960
|
+
expect(emitSpy).toHaveBeenCalledWith(mockRowData);
|
|
961
|
+
});
|
|
962
|
+
|
|
963
|
+
it('should emit the correct rowData directly', () => {
|
|
964
|
+
const emitSpy = jest.spyOn(component.actionButton, 'emit');
|
|
965
|
+
const specificRow: Row = { id: '5', name: 'Direct Action Item' };
|
|
966
|
+
|
|
967
|
+
component.actionRowConfirmation(specificRow);
|
|
968
|
+
|
|
969
|
+
expect(emitSpy).toHaveBeenCalledWith(specificRow);
|
|
970
|
+
});
|
|
971
|
+
|
|
972
|
+
it('should not show confirmation dialog when confirmation is false', () => {
|
|
973
|
+
component.actionRowConfirmation(mockRowData);
|
|
974
|
+
|
|
975
|
+
expect(mockConfirmationService.confirm).not.toHaveBeenCalled();
|
|
976
|
+
});
|
|
977
|
+
});
|
|
978
|
+
});
|
|
979
|
+
|
|
980
|
+
describe('helper methods', () => {
|
|
981
|
+
describe('getRowDataValue', () => {
|
|
982
|
+
it('should return value for a simple field path', () => {
|
|
983
|
+
const rowData = { name: 'Test Item', status: 'active' };
|
|
984
|
+
|
|
985
|
+
const result = component.getRowDataValue(rowData, 'name', 'string');
|
|
986
|
+
|
|
987
|
+
expect(result).toBe('Test Item');
|
|
988
|
+
});
|
|
989
|
+
|
|
990
|
+
it('should return value for a nested field path', () => {
|
|
991
|
+
const rowData = { address: { city: 'Dallas', state: 'TX' } };
|
|
992
|
+
|
|
993
|
+
const result = component.getRowDataValue(rowData, 'address.city', 'string');
|
|
994
|
+
|
|
995
|
+
expect(result).toBe('Dallas');
|
|
996
|
+
});
|
|
997
|
+
|
|
998
|
+
it('should return value for a deeply nested field path', () => {
|
|
999
|
+
const rowData = { user: { profile: { email: 'test@example.com' } } };
|
|
1000
|
+
|
|
1001
|
+
const result = component.getRowDataValue(rowData, 'user.profile.email', 'string');
|
|
1002
|
+
|
|
1003
|
+
expect(result).toBe('test@example.com');
|
|
1004
|
+
});
|
|
1005
|
+
|
|
1006
|
+
it('should return undefined for a non-existent nested path', () => {
|
|
1007
|
+
const rowData = { name: 'Test' };
|
|
1008
|
+
|
|
1009
|
+
const result = component.getRowDataValue(rowData, 'address.city', 'string');
|
|
1010
|
+
|
|
1011
|
+
expect(result).toBeUndefined();
|
|
1012
|
+
});
|
|
1013
|
+
|
|
1014
|
+
it('should format value using DatePipe when type is date', () => {
|
|
1015
|
+
const rowData = { createdAt: '2024-01-15T00:00:00Z' };
|
|
1016
|
+
mockDatePipe.transform.mockReturnValue('01/15/2024');
|
|
1017
|
+
|
|
1018
|
+
const result = component.getRowDataValue(rowData, 'createdAt', 'date');
|
|
1019
|
+
|
|
1020
|
+
expect(mockDatePipe.transform).toHaveBeenCalledWith('2024-01-15T00:00:00Z', 'MM/dd/yyyy');
|
|
1021
|
+
expect(result).toBe('01/15/2024');
|
|
1022
|
+
});
|
|
1023
|
+
|
|
1024
|
+
it('should not call DatePipe when type is not date', () => {
|
|
1025
|
+
const rowData = { name: 'Test' };
|
|
1026
|
+
|
|
1027
|
+
component.getRowDataValue(rowData, 'name', 'string');
|
|
1028
|
+
|
|
1029
|
+
expect(mockDatePipe.transform).not.toHaveBeenCalled();
|
|
1030
|
+
});
|
|
1031
|
+
});
|
|
1032
|
+
|
|
1033
|
+
describe('copyHandler', () => {
|
|
1034
|
+
let mockEvent: { stopPropagation: jest.Mock };
|
|
1035
|
+
let mockWriteText: jest.Mock;
|
|
1036
|
+
|
|
1037
|
+
beforeEach(() => {
|
|
1038
|
+
mockEvent = { stopPropagation: jest.fn() };
|
|
1039
|
+
mockWriteText = jest.fn().mockResolvedValue(undefined);
|
|
1040
|
+
Object.assign(navigator, {
|
|
1041
|
+
clipboard: { writeText: mockWriteText },
|
|
1042
|
+
});
|
|
1043
|
+
// Mock the snackbar component
|
|
1044
|
+
(component as any).atomixSnackbarComponent = { showSnackbar: jest.fn() };
|
|
1045
|
+
});
|
|
1046
|
+
|
|
1047
|
+
it('should stop event propagation', () => {
|
|
1048
|
+
component.copyHandler(mockEvent as any, 'test-value');
|
|
1049
|
+
|
|
1050
|
+
expect(mockEvent.stopPropagation).toHaveBeenCalled();
|
|
1051
|
+
});
|
|
1052
|
+
|
|
1053
|
+
it('should call navigator.clipboard.writeText with the element value', () => {
|
|
1054
|
+
component.copyHandler(mockEvent as any, 'SKU-12345');
|
|
1055
|
+
|
|
1056
|
+
expect(mockWriteText).toHaveBeenCalledWith('SKU-12345');
|
|
1057
|
+
});
|
|
1058
|
+
|
|
1059
|
+
it('should show snackbar with copied message', () => {
|
|
1060
|
+
component.copyHandler(mockEvent as any, 'order-789');
|
|
1061
|
+
|
|
1062
|
+
expect((component as any).atomixSnackbarComponent.showSnackbar).toHaveBeenCalledWith(
|
|
1063
|
+
'Copied order-789 to clipboard'
|
|
1064
|
+
);
|
|
1065
|
+
});
|
|
1066
|
+
});
|
|
1067
|
+
|
|
1068
|
+
describe('shouldShowAction', () => {
|
|
1069
|
+
it('should return true when action is null', () => {
|
|
1070
|
+
expect(component.shouldShowAction(null, {})).toBe(true);
|
|
1071
|
+
});
|
|
1072
|
+
|
|
1073
|
+
it('should return true when action has no showOnlyWhen property', () => {
|
|
1074
|
+
const action = { icon: 'pi pi-pencil', tooltip: 'Edit' };
|
|
1075
|
+
const rowData = { status: 'active' };
|
|
1076
|
+
|
|
1077
|
+
expect(component.shouldShowAction(action, rowData)).toBe(true);
|
|
1078
|
+
});
|
|
1079
|
+
|
|
1080
|
+
it('should return true when row data matches showOnlyWhen condition', () => {
|
|
1081
|
+
const action = { showOnlyWhen: { status: 'active' } };
|
|
1082
|
+
const rowData = { status: 'active', name: 'Item 1' };
|
|
1083
|
+
|
|
1084
|
+
expect(component.shouldShowAction(action, rowData)).toBe(true);
|
|
1085
|
+
});
|
|
1086
|
+
|
|
1087
|
+
it('should return false when row data does not match showOnlyWhen condition', () => {
|
|
1088
|
+
const action = { showOnlyWhen: { status: 'active' } };
|
|
1089
|
+
const rowData = { status: 'inactive', name: 'Item 1' };
|
|
1090
|
+
|
|
1091
|
+
expect(component.shouldShowAction(action, rowData)).toBe(false);
|
|
1092
|
+
});
|
|
1093
|
+
|
|
1094
|
+
it('should match case-insensitively', () => {
|
|
1095
|
+
const action = { showOnlyWhen: { status: 'Active' } };
|
|
1096
|
+
const rowData = { status: 'active' };
|
|
1097
|
+
|
|
1098
|
+
expect(component.shouldShowAction(action, rowData)).toBe(true);
|
|
1099
|
+
});
|
|
1100
|
+
|
|
1101
|
+
it('should return false when row data key is missing', () => {
|
|
1102
|
+
const action = { showOnlyWhen: { status: 'active' } };
|
|
1103
|
+
const rowData = { name: 'Item 1' };
|
|
1104
|
+
|
|
1105
|
+
expect(component.shouldShowAction(action, rowData)).toBe(false);
|
|
1106
|
+
});
|
|
1107
|
+
|
|
1108
|
+
it('should require all showOnlyWhen conditions to match', () => {
|
|
1109
|
+
const action = { showOnlyWhen: { status: 'active', type: 'order' } };
|
|
1110
|
+
const rowData = { status: 'active', type: 'return' };
|
|
1111
|
+
|
|
1112
|
+
expect(component.shouldShowAction(action, rowData)).toBe(false);
|
|
1113
|
+
});
|
|
1114
|
+
|
|
1115
|
+
it('should return true when all multiple conditions match', () => {
|
|
1116
|
+
const action = { showOnlyWhen: { status: 'active', type: 'order' } };
|
|
1117
|
+
const rowData = { status: 'active', type: 'order', name: 'Item' };
|
|
1118
|
+
|
|
1119
|
+
expect(component.shouldShowAction(action, rowData)).toBe(true);
|
|
1120
|
+
});
|
|
1121
|
+
});
|
|
1122
|
+
|
|
1123
|
+
describe('hasChildRows', () => {
|
|
1124
|
+
it('should return false when secondaryRowsKey is not set', () => {
|
|
1125
|
+
component.secondaryRowsKey = '';
|
|
1126
|
+
const rowData = { items: [{ id: 1 }] };
|
|
1127
|
+
|
|
1128
|
+
expect(component.hasChildRows(rowData)).toBe(false);
|
|
1129
|
+
});
|
|
1130
|
+
|
|
1131
|
+
it('should return true when row has child rows array with items', () => {
|
|
1132
|
+
component.secondaryRowsKey = 'items';
|
|
1133
|
+
const rowData = { items: [{ id: 1 }, { id: 2 }] };
|
|
1134
|
+
|
|
1135
|
+
expect(component.hasChildRows(rowData)).toBe(true);
|
|
1136
|
+
});
|
|
1137
|
+
|
|
1138
|
+
it('should return false when row has empty child rows array', () => {
|
|
1139
|
+
component.secondaryRowsKey = 'items';
|
|
1140
|
+
const rowData = { items: [] };
|
|
1141
|
+
|
|
1142
|
+
expect(component.hasChildRows(rowData)).toBe(false);
|
|
1143
|
+
});
|
|
1144
|
+
|
|
1145
|
+
it('should return false when row does not have the secondaryRowsKey property', () => {
|
|
1146
|
+
component.secondaryRowsKey = 'items';
|
|
1147
|
+
const rowData = { name: 'Test' };
|
|
1148
|
+
|
|
1149
|
+
expect(component.hasChildRows(rowData)).toBe(false);
|
|
1150
|
+
});
|
|
1151
|
+
|
|
1152
|
+
it('should return false when child rows value is not an array', () => {
|
|
1153
|
+
component.secondaryRowsKey = 'items';
|
|
1154
|
+
const rowData = { items: 'not-an-array' };
|
|
1155
|
+
|
|
1156
|
+
expect(component.hasChildRows(rowData)).toBe(false);
|
|
1157
|
+
});
|
|
1158
|
+
});
|
|
1159
|
+
|
|
1160
|
+
describe('shouldShowActionButton', () => {
|
|
1161
|
+
it('should return true when no special conditions apply', () => {
|
|
1162
|
+
component.hideMainRowActionsWhenExpanded = false;
|
|
1163
|
+
component.secondaryRowsKey = '';
|
|
1164
|
+
const action = {};
|
|
1165
|
+
const rowData = { name: 'Test' };
|
|
1166
|
+
|
|
1167
|
+
expect(component.shouldShowActionButton(action, rowData)).toBe(true);
|
|
1168
|
+
});
|
|
1169
|
+
|
|
1170
|
+
it('should return false when hideMainRowActionsWhenExpanded is true and row has child rows', () => {
|
|
1171
|
+
component.hideMainRowActionsWhenExpanded = true;
|
|
1172
|
+
component.secondaryRowsKey = 'items';
|
|
1173
|
+
const action = {};
|
|
1174
|
+
const rowData = { items: [{ id: 1 }] };
|
|
1175
|
+
|
|
1176
|
+
expect(component.shouldShowActionButton(action, rowData)).toBe(false);
|
|
1177
|
+
});
|
|
1178
|
+
|
|
1179
|
+
it('should return true when hideMainRowActionsWhenExpanded is true but row has no child rows', () => {
|
|
1180
|
+
component.hideMainRowActionsWhenExpanded = true;
|
|
1181
|
+
component.secondaryRowsKey = 'items';
|
|
1182
|
+
const action = {};
|
|
1183
|
+
const rowData = { items: [] };
|
|
1184
|
+
|
|
1185
|
+
expect(component.shouldShowActionButton(action, rowData)).toBe(true);
|
|
1186
|
+
});
|
|
1187
|
+
|
|
1188
|
+
it('should return false when action.showOnlyWhenNoChildRows is true and row has child rows', () => {
|
|
1189
|
+
component.hideMainRowActionsWhenExpanded = false;
|
|
1190
|
+
component.secondaryRowsKey = 'items';
|
|
1191
|
+
const action = { showOnlyWhenNoChildRows: true };
|
|
1192
|
+
const rowData = { items: [{ id: 1 }] };
|
|
1193
|
+
|
|
1194
|
+
expect(component.shouldShowActionButton(action, rowData)).toBe(false);
|
|
1195
|
+
});
|
|
1196
|
+
|
|
1197
|
+
it('should return true when action.showOnlyWhenNoChildRows is true but row has no child rows', () => {
|
|
1198
|
+
component.hideMainRowActionsWhenExpanded = false;
|
|
1199
|
+
component.secondaryRowsKey = 'items';
|
|
1200
|
+
const action = { showOnlyWhenNoChildRows: true };
|
|
1201
|
+
const rowData = { items: [] };
|
|
1202
|
+
|
|
1203
|
+
expect(component.shouldShowActionButton(action, rowData)).toBe(true);
|
|
1204
|
+
});
|
|
1205
|
+
|
|
1206
|
+
it('should return true when action.showOnlyWhenNoChildRows is false even if row has child rows', () => {
|
|
1207
|
+
component.hideMainRowActionsWhenExpanded = false;
|
|
1208
|
+
component.secondaryRowsKey = 'items';
|
|
1209
|
+
const action = { showOnlyWhenNoChildRows: false };
|
|
1210
|
+
const rowData = { items: [{ id: 1 }] };
|
|
1211
|
+
|
|
1212
|
+
expect(component.shouldShowActionButton(action, rowData)).toBe(true);
|
|
1213
|
+
});
|
|
1214
|
+
});
|
|
1215
|
+
});
|
|
1216
|
+
|
|
1217
|
+
describe('checkbox functionality', () => {
|
|
1218
|
+
const mockRows: Row[] = [
|
|
1219
|
+
{ id: '1', name: 'Item 1', isSelected: false },
|
|
1220
|
+
{ id: '2', name: 'Item 2', isSelected: false },
|
|
1221
|
+
{ id: '3', name: 'Item 3', isSelected: false },
|
|
1222
|
+
];
|
|
1223
|
+
|
|
1224
|
+
beforeEach(() => {
|
|
1225
|
+
component.rows = mockRows.map((row) => ({ ...row }));
|
|
1226
|
+
component.cols = [{ name: 'Name', field: 'name' }];
|
|
1227
|
+
component.isAllSelected = false;
|
|
1228
|
+
});
|
|
1229
|
+
|
|
1230
|
+
describe('isAnyRowSelected', () => {
|
|
1231
|
+
it('should return false and set isAllSelected to false when no rows are selected', () => {
|
|
1232
|
+
component.rows = [
|
|
1233
|
+
{ id: '1', name: 'Item 1', isSelected: false },
|
|
1234
|
+
{ id: '2', name: 'Item 2', isSelected: false },
|
|
1235
|
+
];
|
|
1236
|
+
|
|
1237
|
+
const result = component.isAnyRowSelected();
|
|
1238
|
+
|
|
1239
|
+
expect(result).toBe(false);
|
|
1240
|
+
expect(component.isAllSelected).toBe(false);
|
|
1241
|
+
});
|
|
1242
|
+
|
|
1243
|
+
it('should return true and set isAllSelected to true when some rows are selected', () => {
|
|
1244
|
+
component.rows = [
|
|
1245
|
+
{ id: '1', name: 'Item 1', isSelected: true },
|
|
1246
|
+
{ id: '2', name: 'Item 2', isSelected: false },
|
|
1247
|
+
{ id: '3', name: 'Item 3', isSelected: false },
|
|
1248
|
+
];
|
|
1249
|
+
|
|
1250
|
+
const result = component.isAnyRowSelected();
|
|
1251
|
+
|
|
1252
|
+
expect(result).toBe(true);
|
|
1253
|
+
expect(component.isAllSelected).toBe(true);
|
|
1254
|
+
});
|
|
1255
|
+
|
|
1256
|
+
it('should return false and set isAllSelected to true when ALL rows are selected', () => {
|
|
1257
|
+
component.rows = [
|
|
1258
|
+
{ id: '1', name: 'Item 1', isSelected: true },
|
|
1259
|
+
{ id: '2', name: 'Item 2', isSelected: true },
|
|
1260
|
+
{ id: '3', name: 'Item 3', isSelected: true },
|
|
1261
|
+
];
|
|
1262
|
+
|
|
1263
|
+
const result = component.isAnyRowSelected();
|
|
1264
|
+
|
|
1265
|
+
expect(result).toBe(false);
|
|
1266
|
+
expect(component.isAllSelected).toBe(true);
|
|
1267
|
+
});
|
|
1268
|
+
|
|
1269
|
+
it('should return false when rows is empty (every returns true for empty array)', () => {
|
|
1270
|
+
component.rows = [];
|
|
1271
|
+
|
|
1272
|
+
const result = component.isAnyRowSelected();
|
|
1273
|
+
|
|
1274
|
+
// Array.every() returns true for empty arrays (vacuous truth),
|
|
1275
|
+
// so isAllSelected is set to true and the method returns false
|
|
1276
|
+
expect(result).toBe(false);
|
|
1277
|
+
expect(component.isAllSelected).toBe(true);
|
|
1278
|
+
});
|
|
1279
|
+
});
|
|
1280
|
+
|
|
1281
|
+
describe('toggleAllRows', () => {
|
|
1282
|
+
it('should set all rows isSelected to true when isAllSelected is true', () => {
|
|
1283
|
+
component.isAllSelected = true;
|
|
1284
|
+
|
|
1285
|
+
component.toggleAllRows({ checked: true } as any);
|
|
1286
|
+
|
|
1287
|
+
component.rows.forEach((row) => {
|
|
1288
|
+
expect(row.isSelected).toBe(true);
|
|
1289
|
+
});
|
|
1290
|
+
});
|
|
1291
|
+
|
|
1292
|
+
it('should set all rows isSelected to false when isAllSelected is false', () => {
|
|
1293
|
+
component.rows = [
|
|
1294
|
+
{ id: '1', name: 'Item 1', isSelected: true },
|
|
1295
|
+
{ id: '2', name: 'Item 2', isSelected: true },
|
|
1296
|
+
];
|
|
1297
|
+
component.isAllSelected = false;
|
|
1298
|
+
|
|
1299
|
+
component.toggleAllRows({ checked: false } as any);
|
|
1300
|
+
|
|
1301
|
+
component.rows.forEach((row) => {
|
|
1302
|
+
expect(row.isSelected).toBe(false);
|
|
1303
|
+
});
|
|
1304
|
+
});
|
|
1305
|
+
|
|
1306
|
+
it('should emit headerCheckboxHandler with isAllSelected value', () => {
|
|
1307
|
+
const emitSpy = jest.spyOn(component.headerCheckboxHandler, 'emit');
|
|
1308
|
+
component.isAllSelected = true;
|
|
1309
|
+
|
|
1310
|
+
component.toggleAllRows({ checked: true } as any);
|
|
1311
|
+
|
|
1312
|
+
expect(emitSpy).toHaveBeenCalledWith(true);
|
|
1313
|
+
});
|
|
1314
|
+
|
|
1315
|
+
it('should emit headerCheckboxHandler with false when deselecting all', () => {
|
|
1316
|
+
const emitSpy = jest.spyOn(component.headerCheckboxHandler, 'emit');
|
|
1317
|
+
component.isAllSelected = false;
|
|
1318
|
+
|
|
1319
|
+
component.toggleAllRows({ checked: false } as any);
|
|
1320
|
+
|
|
1321
|
+
expect(emitSpy).toHaveBeenCalledWith(false);
|
|
1322
|
+
});
|
|
1323
|
+
|
|
1324
|
+
it('should emit checkboxHandler when toggling all rows', () => {
|
|
1325
|
+
const emitSpy = jest.spyOn(component.checkboxHandler, 'emit');
|
|
1326
|
+
component.isAllSelected = true;
|
|
1327
|
+
|
|
1328
|
+
component.toggleAllRows({ checked: true } as any);
|
|
1329
|
+
|
|
1330
|
+
expect(emitSpy).toHaveBeenCalled();
|
|
1331
|
+
});
|
|
1332
|
+
});
|
|
1333
|
+
|
|
1334
|
+
describe('singleCheckboxHandler', () => {
|
|
1335
|
+
it('should set isAllSelected to true', () => {
|
|
1336
|
+
component.isAllSelected = false;
|
|
1337
|
+
const row = { id: '1', name: 'Item 1', isSelected: true };
|
|
1338
|
+
|
|
1339
|
+
component.singleCheckboxHandler({ checked: true } as any, row);
|
|
1340
|
+
|
|
1341
|
+
expect(component.isAllSelected).toBe(true);
|
|
1342
|
+
});
|
|
1343
|
+
|
|
1344
|
+
it('should emit headerCheckboxHandler with false', () => {
|
|
1345
|
+
const emitSpy = jest.spyOn(component.headerCheckboxHandler, 'emit');
|
|
1346
|
+
const row = { id: '1', name: 'Item 1', isSelected: true };
|
|
1347
|
+
|
|
1348
|
+
component.singleCheckboxHandler({ checked: true } as any, row);
|
|
1349
|
+
|
|
1350
|
+
expect(emitSpy).toHaveBeenCalledWith(false);
|
|
1351
|
+
});
|
|
1352
|
+
|
|
1353
|
+
it('should emit checkboxHandler', () => {
|
|
1354
|
+
const emitSpy = jest.spyOn(component.checkboxHandler, 'emit');
|
|
1355
|
+
const row = { id: '1', name: 'Item 1', isSelected: true };
|
|
1356
|
+
|
|
1357
|
+
component.singleCheckboxHandler({ checked: true } as any, row);
|
|
1358
|
+
|
|
1359
|
+
expect(emitSpy).toHaveBeenCalled();
|
|
1360
|
+
});
|
|
1361
|
+
|
|
1362
|
+
it('should emit headerCheckboxHandler with false regardless of row state', () => {
|
|
1363
|
+
const emitSpy = jest.spyOn(component.headerCheckboxHandler, 'emit');
|
|
1364
|
+
const row = { id: '2', name: 'Item 2', isSelected: false };
|
|
1365
|
+
|
|
1366
|
+
component.singleCheckboxHandler({ checked: false } as any, row);
|
|
1367
|
+
|
|
1368
|
+
expect(emitSpy).toHaveBeenCalledWith(false);
|
|
1369
|
+
});
|
|
1370
|
+
});
|
|
1371
|
+
|
|
1372
|
+
describe('headerCheckboxHandler EventEmitter', () => {
|
|
1373
|
+
it('should emit boolean values when subscribing to headerCheckboxHandler', () => {
|
|
1374
|
+
const emittedValues: boolean[] = [];
|
|
1375
|
+
component.headerCheckboxHandler.subscribe((value) => emittedValues.push(value));
|
|
1376
|
+
|
|
1377
|
+
component.isAllSelected = true;
|
|
1378
|
+
component.toggleAllRows({ checked: true } as any);
|
|
1379
|
+
|
|
1380
|
+
component.isAllSelected = false;
|
|
1381
|
+
component.toggleAllRows({ checked: false } as any);
|
|
1382
|
+
|
|
1383
|
+
expect(emittedValues).toEqual([true, false]);
|
|
1384
|
+
});
|
|
1385
|
+
|
|
1386
|
+
it('should emit false from singleCheckboxHandler calls', () => {
|
|
1387
|
+
const emittedValues: boolean[] = [];
|
|
1388
|
+
component.headerCheckboxHandler.subscribe((value) => emittedValues.push(value));
|
|
1389
|
+
|
|
1390
|
+
const row1 = { id: '1', name: 'Item 1', isSelected: true };
|
|
1391
|
+
const row2 = { id: '2', name: 'Item 2', isSelected: true };
|
|
1392
|
+
|
|
1393
|
+
component.singleCheckboxHandler({ checked: true } as any, row1);
|
|
1394
|
+
component.singleCheckboxHandler({ checked: true } as any, row2);
|
|
1395
|
+
|
|
1396
|
+
expect(emittedValues).toEqual([false, false]);
|
|
1397
|
+
});
|
|
1398
|
+
});
|
|
1399
|
+
});
|
|
1400
|
+
|
|
1401
|
+
describe('dropdown and child row actions', () => {
|
|
1402
|
+
beforeEach(() => {
|
|
1403
|
+
component.rows = [
|
|
1404
|
+
{ id: '1', name: 'Item 1', status: 'active' },
|
|
1405
|
+
{ id: '2', name: 'Item 2', status: 'inactive' },
|
|
1406
|
+
];
|
|
1407
|
+
component.cols = [{ name: 'Name', field: 'name' }];
|
|
1408
|
+
});
|
|
1409
|
+
|
|
1410
|
+
describe('dropdownHandler', () => {
|
|
1411
|
+
it('should emit pageDropdownChange with the event value', () => {
|
|
1412
|
+
const emitSpy = jest.spyOn(component.pageDropdownChange, 'emit');
|
|
1413
|
+
|
|
1414
|
+
component.dropdownHandler({ value: 50 });
|
|
1415
|
+
|
|
1416
|
+
expect(emitSpy).toHaveBeenCalledWith(50);
|
|
1417
|
+
});
|
|
1418
|
+
|
|
1419
|
+
it('should emit pageDropdownChange with undefined when event has no value', () => {
|
|
1420
|
+
const emitSpy = jest.spyOn(component.pageDropdownChange, 'emit');
|
|
1421
|
+
|
|
1422
|
+
component.dropdownHandler({});
|
|
1423
|
+
|
|
1424
|
+
expect(emitSpy).toHaveBeenCalledWith(undefined);
|
|
1425
|
+
});
|
|
1426
|
+
|
|
1427
|
+
it('should emit pageDropdownChange with undefined when event is null', () => {
|
|
1428
|
+
const emitSpy = jest.spyOn(component.pageDropdownChange, 'emit');
|
|
1429
|
+
|
|
1430
|
+
component.dropdownHandler(null);
|
|
1431
|
+
|
|
1432
|
+
expect(emitSpy).toHaveBeenCalledWith(undefined);
|
|
1433
|
+
});
|
|
1434
|
+
|
|
1435
|
+
it('should emit the correct value for different page sizes', () => {
|
|
1436
|
+
const emittedValues: any[] = [];
|
|
1437
|
+
component.pageDropdownChange.subscribe((value) => emittedValues.push(value));
|
|
1438
|
+
|
|
1439
|
+
component.dropdownHandler({ value: 10 });
|
|
1440
|
+
component.dropdownHandler({ value: 25 });
|
|
1441
|
+
component.dropdownHandler({ value: 100 });
|
|
1442
|
+
|
|
1443
|
+
expect(emittedValues).toEqual([10, 25, 100]);
|
|
1444
|
+
});
|
|
1445
|
+
});
|
|
1446
|
+
|
|
1447
|
+
describe('handleActionClick', () => {
|
|
1448
|
+
it('should call the action click handler with the row data', () => {
|
|
1449
|
+
const mockClick = jest.fn();
|
|
1450
|
+
const action = { click: mockClick, icon: 'pi pi-pencil' };
|
|
1451
|
+
const rowData = { id: '1', name: 'Item 1' };
|
|
1452
|
+
|
|
1453
|
+
component.handleActionClick(action, rowData);
|
|
1454
|
+
|
|
1455
|
+
expect(mockClick).toHaveBeenCalledWith(rowData);
|
|
1456
|
+
});
|
|
1457
|
+
|
|
1458
|
+
it('should not throw when action has no click handler', () => {
|
|
1459
|
+
const action = { icon: 'pi pi-pencil' };
|
|
1460
|
+
const rowData = { id: '1', name: 'Item 1' };
|
|
1461
|
+
|
|
1462
|
+
expect(() => component.handleActionClick(action, rowData)).not.toThrow();
|
|
1463
|
+
});
|
|
1464
|
+
|
|
1465
|
+
it('should pass the correct row data to the click handler', () => {
|
|
1466
|
+
const mockClick = jest.fn();
|
|
1467
|
+
const action = { click: mockClick };
|
|
1468
|
+
const rowData = { id: '99', name: 'Special', status: 'pending', amount: 42.5 };
|
|
1469
|
+
|
|
1470
|
+
component.handleActionClick(action, rowData);
|
|
1471
|
+
|
|
1472
|
+
expect(mockClick).toHaveBeenCalledWith(rowData);
|
|
1473
|
+
});
|
|
1474
|
+
|
|
1475
|
+
it('should not call click when action.click is undefined', () => {
|
|
1476
|
+
const action = { click: undefined, icon: 'pi pi-trash' };
|
|
1477
|
+
const rowData = { id: '1', name: 'Item 1' };
|
|
1478
|
+
|
|
1479
|
+
expect(() => component.handleActionClick(action, rowData)).not.toThrow();
|
|
1480
|
+
});
|
|
1481
|
+
});
|
|
1482
|
+
|
|
1483
|
+
describe('handleChildActionClick', () => {
|
|
1484
|
+
it('should call the action click handler when action has a click function', () => {
|
|
1485
|
+
const mockClick = jest.fn();
|
|
1486
|
+
const action = { click: mockClick, icon: 'pi pi-eye' };
|
|
1487
|
+
const rowData = { id: 'child-1', name: 'Child Item' };
|
|
1488
|
+
|
|
1489
|
+
component.handleChildActionClick(action, rowData);
|
|
1490
|
+
|
|
1491
|
+
expect(mockClick).toHaveBeenCalledWith(rowData);
|
|
1492
|
+
});
|
|
1493
|
+
|
|
1494
|
+
it('should not emit childRowAction when action has a click handler', () => {
|
|
1495
|
+
const emitSpy = jest.spyOn(component.childRowAction, 'emit');
|
|
1496
|
+
const mockClick = jest.fn();
|
|
1497
|
+
const action = { click: mockClick };
|
|
1498
|
+
const rowData = { id: 'child-1', name: 'Child Item' };
|
|
1499
|
+
|
|
1500
|
+
component.handleChildActionClick(action, rowData);
|
|
1501
|
+
|
|
1502
|
+
expect(emitSpy).not.toHaveBeenCalled();
|
|
1503
|
+
});
|
|
1504
|
+
|
|
1505
|
+
it('should emit childRowAction with action name when no click handler exists', () => {
|
|
1506
|
+
const emitSpy = jest.spyOn(component.childRowAction, 'emit');
|
|
1507
|
+
const action = { action: 'edit', icon: 'pi pi-pencil' };
|
|
1508
|
+
const rowData = { id: 'child-1', name: 'Child Item' };
|
|
1509
|
+
|
|
1510
|
+
component.handleChildActionClick(action, rowData);
|
|
1511
|
+
|
|
1512
|
+
expect(emitSpy).toHaveBeenCalledWith({ action: 'edit', childRow: rowData });
|
|
1513
|
+
});
|
|
1514
|
+
|
|
1515
|
+
it('should use tooltip as action name when action.action is not defined', () => {
|
|
1516
|
+
const emitSpy = jest.spyOn(component.childRowAction, 'emit');
|
|
1517
|
+
const action = { tooltip: 'Delete', icon: 'pi pi-trash' };
|
|
1518
|
+
const rowData = { id: 'child-2', name: 'Child Item 2' };
|
|
1519
|
+
|
|
1520
|
+
component.handleChildActionClick(action, rowData);
|
|
1521
|
+
|
|
1522
|
+
expect(emitSpy).toHaveBeenCalledWith({ action: 'Delete', childRow: rowData });
|
|
1523
|
+
});
|
|
1524
|
+
|
|
1525
|
+
it('should use the action object itself as action name when neither action nor tooltip exist', () => {
|
|
1526
|
+
const emitSpy = jest.spyOn(component.childRowAction, 'emit');
|
|
1527
|
+
const action = { icon: 'pi pi-check' };
|
|
1528
|
+
const rowData = { id: 'child-3', name: 'Child Item 3' };
|
|
1529
|
+
|
|
1530
|
+
component.handleChildActionClick(action, rowData);
|
|
1531
|
+
|
|
1532
|
+
// actionName = action?.action || action?.tooltip || action
|
|
1533
|
+
// Both action.action and action.tooltip are undefined, so it falls through to the action object itself
|
|
1534
|
+
expect(emitSpy).toHaveBeenCalledWith({ action: { icon: 'pi pi-check' }, childRow: rowData });
|
|
1535
|
+
});
|
|
1536
|
+
|
|
1537
|
+
it('should prefer action.action over action.tooltip for the action name', () => {
|
|
1538
|
+
const emitSpy = jest.spyOn(component.childRowAction, 'emit');
|
|
1539
|
+
const action = { action: 'view', tooltip: 'View Details', icon: 'pi pi-eye' };
|
|
1540
|
+
const rowData = { id: 'child-4', name: 'Child Item 4' };
|
|
1541
|
+
|
|
1542
|
+
component.handleChildActionClick(action, rowData);
|
|
1543
|
+
|
|
1544
|
+
expect(emitSpy).toHaveBeenCalledWith({ action: 'view', childRow: rowData });
|
|
1545
|
+
});
|
|
1546
|
+
});
|
|
1547
|
+
|
|
1548
|
+
describe('handlePageChange', () => {
|
|
1549
|
+
it('should emit pageChange with the event', () => {
|
|
1550
|
+
const emitSpy = jest.fn();
|
|
1551
|
+
component.pageChange.subscribe(emitSpy);
|
|
1552
|
+
|
|
1553
|
+
const event = { page: 2, rows: 10 };
|
|
1554
|
+
component.handlePageChange(event);
|
|
1555
|
+
|
|
1556
|
+
expect(emitSpy).toHaveBeenCalledWith(event);
|
|
1557
|
+
});
|
|
1558
|
+
});
|
|
1559
|
+
|
|
1560
|
+
describe('isString', () => {
|
|
1561
|
+
it('should return true for string values', () => {
|
|
1562
|
+
expect(component.isString('hello')).toBe(true);
|
|
1563
|
+
expect(component.isString('')).toBe(true);
|
|
1564
|
+
});
|
|
1565
|
+
|
|
1566
|
+
it('should return false for non-string values', () => {
|
|
1567
|
+
expect(component.isString(123)).toBe(false);
|
|
1568
|
+
expect(component.isString(null)).toBe(false);
|
|
1569
|
+
expect(component.isString(undefined)).toBe(false);
|
|
1570
|
+
expect(component.isString({})).toBe(false);
|
|
1571
|
+
expect(component.isString([])).toBe(false);
|
|
1572
|
+
});
|
|
1573
|
+
});
|
|
1574
|
+
|
|
1575
|
+
describe('handleDateRangeFilter', () => {
|
|
1576
|
+
it('should call filterCallback when value is an array of 2 Date objects', () => {
|
|
1577
|
+
const filterCallback = jest.fn();
|
|
1578
|
+
const startDate = new Date(2024, 0, 1);
|
|
1579
|
+
const endDate = new Date(2024, 0, 31);
|
|
1580
|
+
|
|
1581
|
+
component.handleDateRangeFilter([startDate, endDate], filterCallback);
|
|
1582
|
+
|
|
1583
|
+
expect(filterCallback).toHaveBeenCalledWith([startDate, endDate]);
|
|
1584
|
+
});
|
|
1585
|
+
|
|
1586
|
+
it('should not call filterCallback when value is an array with only 1 Date', () => {
|
|
1587
|
+
const filterCallback = jest.fn();
|
|
1588
|
+
const startDate = new Date(2024, 0, 1);
|
|
1589
|
+
|
|
1590
|
+
component.handleDateRangeFilter([startDate], filterCallback);
|
|
1591
|
+
|
|
1592
|
+
expect(filterCallback).not.toHaveBeenCalled();
|
|
1593
|
+
});
|
|
1594
|
+
|
|
1595
|
+
it('should not call filterCallback when value is an array with non-Date items', () => {
|
|
1596
|
+
const filterCallback = jest.fn();
|
|
1597
|
+
|
|
1598
|
+
component.handleDateRangeFilter(['2024-01-01', '2024-01-31'], filterCallback);
|
|
1599
|
+
|
|
1600
|
+
expect(filterCallback).not.toHaveBeenCalled();
|
|
1601
|
+
});
|
|
1602
|
+
|
|
1603
|
+
it('should call filterCallback with null when value is null (clear filter)', () => {
|
|
1604
|
+
const filterCallback = jest.fn();
|
|
1605
|
+
|
|
1606
|
+
component.handleDateRangeFilter(null, filterCallback);
|
|
1607
|
+
|
|
1608
|
+
expect(filterCallback).toHaveBeenCalledWith(null);
|
|
1609
|
+
});
|
|
1610
|
+
|
|
1611
|
+
it('should not call filterCallback when value is undefined', () => {
|
|
1612
|
+
const filterCallback = jest.fn();
|
|
1613
|
+
|
|
1614
|
+
component.handleDateRangeFilter(undefined, filterCallback);
|
|
1615
|
+
|
|
1616
|
+
expect(filterCallback).not.toHaveBeenCalled();
|
|
1617
|
+
});
|
|
1618
|
+
|
|
1619
|
+
it('should not call filterCallback when value is an empty array', () => {
|
|
1620
|
+
const filterCallback = jest.fn();
|
|
1621
|
+
|
|
1622
|
+
component.handleDateRangeFilter([], filterCallback);
|
|
1623
|
+
|
|
1624
|
+
expect(filterCallback).not.toHaveBeenCalled();
|
|
1625
|
+
});
|
|
1626
|
+
|
|
1627
|
+
it('should not call filterCallback when array has 2 items but one is not a Date', () => {
|
|
1628
|
+
const filterCallback = jest.fn();
|
|
1629
|
+
const startDate = new Date(2024, 0, 1);
|
|
1630
|
+
|
|
1631
|
+
component.handleDateRangeFilter([startDate, '2024-01-31'], filterCallback);
|
|
1632
|
+
|
|
1633
|
+
expect(filterCallback).not.toHaveBeenCalled();
|
|
1634
|
+
});
|
|
1635
|
+
|
|
1636
|
+
it('should call filterCallback with the exact date array passed in', () => {
|
|
1637
|
+
const filterCallback = jest.fn();
|
|
1638
|
+
const startDate = new Date(2024, 5, 15);
|
|
1639
|
+
const endDate = new Date(2024, 11, 31);
|
|
1640
|
+
const dateArray = [startDate, endDate];
|
|
1641
|
+
|
|
1642
|
+
component.handleDateRangeFilter(dateArray, filterCallback);
|
|
1643
|
+
|
|
1644
|
+
expect(filterCallback).toHaveBeenCalledWith(dateArray);
|
|
1645
|
+
});
|
|
1646
|
+
});
|
|
1647
|
+
});
|
|
1648
|
+
});
|