@memberjunction/ng-pagination 5.41.0 → 5.43.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.
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=pagination.component.dom.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pagination.component.dom.test.d.ts","sourceRoot":"","sources":["../../src/lib/pagination.component.dom.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,92 @@
1
+ import { describe, it, expect, vi } from 'vitest';
2
+ import { TestBed } from '@angular/core/testing';
3
+ import { PaginationComponent } from './pagination.component';
4
+ /**
5
+ * DOM-level spec for `<mj-pagination>`. The component's whole reason to exist is
6
+ * template gating + click wiring:
7
+ * - it renders nothing unless there is more than one page,
8
+ * - first/prev are disabled on page 1, next/last on the last page,
9
+ * - clicking a nav button emits a `PageChange` with the right StartRow.
10
+ *
11
+ * None of that is observable from the class alone — these assertions drive the
12
+ * rendered buttons and read the emitted `@Output`.
13
+ */
14
+ describe('PaginationComponent (DOM)', () => {
15
+ function render(setup) {
16
+ const fixture = TestBed.createComponent(PaginationComponent);
17
+ setup(fixture.componentInstance);
18
+ fixture.detectChanges();
19
+ return { fixture, host: fixture.nativeElement };
20
+ }
21
+ function buttonByTitle(host, title) {
22
+ const btn = host.querySelector(`button[title="${title}"]`);
23
+ if (!btn)
24
+ throw new Error(`No pager button with title="${title}"`);
25
+ return btn;
26
+ }
27
+ it('renders nothing when there is a single page of data', () => {
28
+ const { host } = render((c) => {
29
+ c.TotalRowCount = 50;
30
+ c.PageSize = 100;
31
+ c.PageNumber = 1;
32
+ });
33
+ expect(host.querySelector('.pagination')).toBeNull();
34
+ });
35
+ it('renders the pager and a "from-to of total" summary across multiple pages', () => {
36
+ const { host } = render((c) => {
37
+ c.TotalRowCount = 250;
38
+ c.PageSize = 100;
39
+ c.PageNumber = 2;
40
+ });
41
+ expect(host.querySelector('.pagination')).not.toBeNull();
42
+ // DisplayFrom = 101, DisplayTo = 200, total 250 (formatted with the number pipe).
43
+ expect(host.querySelector('.pager-summary')?.textContent?.replace(/\s+/g, ' ').trim()).toBe('101-200 of 250');
44
+ expect(host.querySelector('.pager-page-info')?.textContent?.replace(/\s+/g, ' ').trim()).toBe('Page 2 of 3');
45
+ });
46
+ it('disables first/prev on the first page and enables next/last', () => {
47
+ const { host } = render((c) => {
48
+ c.TotalRowCount = 250;
49
+ c.PageSize = 100;
50
+ c.PageNumber = 1;
51
+ });
52
+ expect(buttonByTitle(host, 'First page').disabled).toBe(true);
53
+ expect(buttonByTitle(host, 'Previous page').disabled).toBe(true);
54
+ expect(buttonByTitle(host, 'Next page').disabled).toBe(false);
55
+ expect(buttonByTitle(host, 'Last page').disabled).toBe(false);
56
+ });
57
+ it('emits PageChange with the correct StartRow when Next is clicked', () => {
58
+ const events = [];
59
+ const { fixture, host } = render((c) => {
60
+ c.TotalRowCount = 250;
61
+ c.PageSize = 100;
62
+ c.PageNumber = 1;
63
+ });
64
+ fixture.componentInstance.PageChange.subscribe((e) => events.push(e));
65
+ buttonByTitle(host, 'Next page').click();
66
+ expect(events).toEqual([{ PageNumber: 2, PageSize: 100, StartRow: 100 }]);
67
+ });
68
+ it('does not emit when a disabled button is clicked', () => {
69
+ const spy = vi.fn();
70
+ const { fixture, host } = render((c) => {
71
+ c.TotalRowCount = 250;
72
+ c.PageSize = 100;
73
+ c.PageNumber = 1;
74
+ });
75
+ fixture.componentInstance.PageChange.subscribe(spy);
76
+ // Previous is disabled on page 1; clicking the disabled button must be a no-op.
77
+ buttonByTitle(host, 'Previous page').click();
78
+ expect(spy).not.toHaveBeenCalled();
79
+ });
80
+ it('shows the loading spinner and disables navigation while IsLoading', () => {
81
+ const { host } = render((c) => {
82
+ c.TotalRowCount = 250;
83
+ c.PageSize = 100;
84
+ c.PageNumber = 2;
85
+ c.IsLoading = true;
86
+ });
87
+ expect(host.querySelector('.pager-loading')).not.toBeNull();
88
+ expect(buttonByTitle(host, 'Next page').disabled).toBe(true);
89
+ expect(buttonByTitle(host, 'Previous page').disabled).toBe(true);
90
+ });
91
+ });
92
+ //# sourceMappingURL=pagination.component.dom.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pagination.component.dom.test.js","sourceRoot":"","sources":["../../src/lib/pagination.component.dom.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { describe, it, expect, vi } from 'vitest';\nimport { ComponentFixture, TestBed } from '@angular/core/testing';\nimport { PaginationComponent, PageChangeEvent } from './pagination.component';\n\n/**\n * DOM-level spec for `<mj-pagination>`. The component's whole reason to exist is\n * template gating + click wiring:\n * - it renders nothing unless there is more than one page,\n * - first/prev are disabled on page 1, next/last on the last page,\n * - clicking a nav button emits a `PageChange` with the right StartRow.\n *\n * None of that is observable from the class alone — these assertions drive the\n * rendered buttons and read the emitted `@Output`.\n */\ndescribe('PaginationComponent (DOM)', () => {\n function render(\n setup: (c: PaginationComponent) => void,\n ): { fixture: ComponentFixture<PaginationComponent>; host: HTMLElement } {\n const fixture = TestBed.createComponent(PaginationComponent);\n setup(fixture.componentInstance);\n fixture.detectChanges();\n return { fixture, host: fixture.nativeElement as HTMLElement };\n }\n\n function buttonByTitle(host: HTMLElement, title: string): HTMLButtonElement {\n const btn = host.querySelector(`button[title=\"${title}\"]`) as HTMLButtonElement | null;\n if (!btn) throw new Error(`No pager button with title=\"${title}\"`);\n return btn;\n }\n\n it('renders nothing when there is a single page of data', () => {\n const { host } = render((c) => {\n c.TotalRowCount = 50;\n c.PageSize = 100;\n c.PageNumber = 1;\n });\n expect(host.querySelector('.pagination')).toBeNull();\n });\n\n it('renders the pager and a \"from-to of total\" summary across multiple pages', () => {\n const { host } = render((c) => {\n c.TotalRowCount = 250;\n c.PageSize = 100;\n c.PageNumber = 2;\n });\n expect(host.querySelector('.pagination')).not.toBeNull();\n // DisplayFrom = 101, DisplayTo = 200, total 250 (formatted with the number pipe).\n expect(host.querySelector('.pager-summary')?.textContent?.replace(/\\s+/g, ' ').trim()).toBe(\n '101-200 of 250',\n );\n expect(host.querySelector('.pager-page-info')?.textContent?.replace(/\\s+/g, ' ').trim()).toBe(\n 'Page 2 of 3',\n );\n });\n\n it('disables first/prev on the first page and enables next/last', () => {\n const { host } = render((c) => {\n c.TotalRowCount = 250;\n c.PageSize = 100;\n c.PageNumber = 1;\n });\n expect(buttonByTitle(host, 'First page').disabled).toBe(true);\n expect(buttonByTitle(host, 'Previous page').disabled).toBe(true);\n expect(buttonByTitle(host, 'Next page').disabled).toBe(false);\n expect(buttonByTitle(host, 'Last page').disabled).toBe(false);\n });\n\n it('emits PageChange with the correct StartRow when Next is clicked', () => {\n const events: PageChangeEvent[] = [];\n const { fixture, host } = render((c) => {\n c.TotalRowCount = 250;\n c.PageSize = 100;\n c.PageNumber = 1;\n });\n fixture.componentInstance.PageChange.subscribe((e) => events.push(e));\n\n buttonByTitle(host, 'Next page').click();\n\n expect(events).toEqual([{ PageNumber: 2, PageSize: 100, StartRow: 100 }]);\n });\n\n it('does not emit when a disabled button is clicked', () => {\n const spy = vi.fn();\n const { fixture, host } = render((c) => {\n c.TotalRowCount = 250;\n c.PageSize = 100;\n c.PageNumber = 1;\n });\n fixture.componentInstance.PageChange.subscribe(spy);\n\n // Previous is disabled on page 1; clicking the disabled button must be a no-op.\n buttonByTitle(host, 'Previous page').click();\n\n expect(spy).not.toHaveBeenCalled();\n });\n\n it('shows the loading spinner and disables navigation while IsLoading', () => {\n const { host } = render((c) => {\n c.TotalRowCount = 250;\n c.PageSize = 100;\n c.PageNumber = 2;\n c.IsLoading = true;\n });\n expect(host.querySelector('.pager-loading')).not.toBeNull();\n expect(buttonByTitle(host, 'Next page').disabled).toBe(true);\n expect(buttonByTitle(host, 'Previous page').disabled).toBe(true);\n });\n});\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@memberjunction/ng-pagination",
3
- "version": "5.41.0",
3
+ "version": "5.43.0",
4
4
  "description": "MemberJunction: Reusable pagination component for server-side paged data with first/prev/next/last navigation",
5
5
  "main": "./dist/public-api.js",
6
6
  "typings": "./dist/public-api.d.ts",