Skip to content

Commit e5317fd

Browse files
committed
feat(foxy-pagination): make limit and offset configurable
1 parent d6c01e6 commit e5317fd

File tree

33 files changed

+753
-739
lines changed

33 files changed

+753
-739
lines changed
+127-129
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
1-
import { Rels } from '@foxy.io/sdk/backend';
2-
import { Resource } from '@foxy.io/sdk/core';
1+
import type { InternalNumberControl } from '../../internal/InternalNumberControl';
2+
import type { FetchEvent } from '../NucleonElement/FetchEvent';
3+
import type { Resource } from '@foxy.io/sdk/core';
4+
import type { Rels } from '@foxy.io/sdk/backend';
5+
6+
import './index';
7+
38
import { expect, fixture, html, waitUntil } from '@open-wc/testing';
4-
import { LitElement } from 'lit-element';
5-
import { createRouter } from '../../../server/index';
6-
import { getByKey } from '../../../testgen/getByKey';
7-
import { getByTestId } from '../../../testgen/getByTestId';
8-
import { getTestData } from '../../../testgen/getTestData';
9-
import { FetchEvent } from '../NucleonElement/FetchEvent';
109
import { NucleonElement } from '../NucleonElement/NucleonElement';
11-
import { Pagination } from './index';
10+
import { getByTestClass } from '../../../testgen/getByTestClass';
11+
import { createRouter } from '../../../server/index';
12+
import { Pagination } from './Pagination';
13+
import { LitElement } from 'lit-element';
1214

1315
type TestData = Resource<Rels.CouponCodes>;
1416
customElements.define('test-page-element', class extends NucleonElement<TestData> {});
@@ -46,159 +48,155 @@ describe('Pagination', () => {
4648
);
4749
});
4850

49-
(['next', 'last', 'prev', 'first'] as const).forEach(rel => {
50-
it(`sets "${rel}" URL as "href" on the page element when "${rel}" button is clicked`, async () => {
51-
const router = createRouter();
52-
const handle = (evt: FetchEvent) => router.handleEvent(evt);
53-
const element = await fixture(html`
54-
<foxy-pagination first="https://demo.api/hapi/coupon_codes?limit=1&offset=2">
55-
<test-page-element @fetch=${handle}></test-page-element>
56-
</foxy-pagination>
57-
`);
58-
59-
const page = element.firstElementChild as NucleonElement<TestData>;
60-
await waitUntil(() => page.in({ idle: 'snapshot' }));
61-
62-
const newHref = page.data?._links[rel].href;
63-
const button = await getByTestId(element, rel);
64-
button?.click();
65-
66-
expect(page).to.have.property('href', newHref);
67-
});
68-
});
69-
70-
it('disables "prev" and "first" buttons on first page', async () => {
51+
it('renders limit selector', async () => {
7152
const router = createRouter();
72-
const handle = (evt: FetchEvent) => router.handleEvent(evt);
73-
const element = await fixture(html`
74-
<foxy-pagination first="https://demo.api/hapi/coupon_codes">
75-
<test-page-element @fetch=${handle}></test-page-element>
53+
const element = await fixture<Pagination>(html`
54+
<foxy-pagination first="https://demo.api/hapi/coupon_codes?limit=3">
55+
<test-page-element @fetch=${(evt: FetchEvent) => router.handleEvent(evt)}>
56+
</test-page-element>
7657
</foxy-pagination>
7758
`);
7859

79-
const page = element.firstElementChild as NucleonElement<TestData>;
80-
await waitUntil(() => page.in({ idle: 'snapshot' }));
81-
82-
expect(await getByTestId(element, 'first')).to.have.attribute('disabled');
83-
expect(await getByTestId(element, 'prev')).to.have.attribute('disabled');
60+
const pageElement = element.firstElementChild as NucleonElement<TestData>;
61+
await waitUntil(() => pageElement.in('idle'));
62+
63+
const labelI18n = element.renderRoot.querySelector('foxy-i18n[infer=""][key="per_page"]');
64+
const label = labelI18n?.closest('label');
65+
const select = label?.htmlFor
66+
? element.renderRoot.querySelector<HTMLSelectElement>(`#${label.htmlFor}`)
67+
: null;
68+
69+
expect(select).to.exist;
70+
expect(select?.options.item(0)).to.have.property('value', '3');
71+
expect(select?.options.item(1)).to.have.property('value', '20');
72+
expect(select?.options.item(2)).to.have.property('value', '50');
73+
expect(select?.options.item(3)).to.have.property('value', '100');
74+
expect(select?.options.item(4)).to.have.property('value', '150');
75+
expect(select?.options.item(5)).to.have.property('value', '200');
76+
expect(select?.options.item(6)).to.not.exist;
77+
78+
select!.value = '20';
79+
select!.dispatchEvent(new Event('change'));
80+
await element.requestUpdate('__page');
81+
expect(pageElement.href).to.equal('https://demo.api/hapi/coupon_codes?limit=20');
8482
});
8583

86-
it('disables "last" and "next" buttons on last page', async () => {
84+
it('renders simple pagination', async () => {
8785
const router = createRouter();
88-
const handle = (evt: FetchEvent) => router.handleEvent(evt);
89-
const data = await getTestData<TestData>('./hapi/coupon_codes');
90-
91-
const element = await fixture(html`
92-
<foxy-pagination first=${data._links.last.href}>
93-
<test-page-element @fetch=${handle}></test-page-element>
86+
const element = await fixture<Pagination>(html`
87+
<foxy-pagination first="https://demo.api/hapi/coupon_codes?limit=50">
88+
<test-page-element @fetch=${(evt: FetchEvent) => router.handleEvent(evt)}>
89+
</test-page-element>
9490
</foxy-pagination>
9591
`);
9692

97-
const page = element.firstElementChild as NucleonElement<TestData>;
98-
await waitUntil(() => page.in({ idle: 'snapshot' }));
93+
const pageElement = element.firstElementChild as NucleonElement<TestData>;
94+
await waitUntil(() => pageElement.in('idle'));
9995

100-
expect(await getByTestId(element, 'last')).to.have.attribute('disabled');
101-
expect(await getByTestId(element, 'next')).to.have.attribute('disabled');
102-
});
103-
104-
it('hides all buttons while loading', async () => {
105-
const router = createRouter();
106-
const handle = (evt: FetchEvent) => router.handleEvent(evt);
107-
const element = await fixture(html`
108-
<foxy-pagination first="https://demo.api/virtual/stall">
109-
<test-page-element @fetch=${handle}></test-page-element>
110-
</foxy-pagination>
111-
`);
96+
const jumpToLabel = element.renderRoot.querySelector('foxy-i18n[infer=""][key="jump_to"]');
97+
expect(jumpToLabel).to.exist;
11298

113-
const page = element.firstElementChild as NucleonElement<TestData>;
114-
await waitUntil(() => page.in('busy'));
99+
const buttons = await getByTestClass(element, 'page-link');
100+
expect(buttons).to.have.length(2);
101+
expect(buttons[0].textContent?.trim()).to.equal('1');
102+
expect(buttons[0]).to.have.attribute('disabled');
103+
expect(buttons[1].textContent?.trim()).to.equal('2');
104+
expect(buttons[1]).to.not.have.attribute('disabled');
115105

116-
expect(await getByTestId(element, 'first')).to.not.exist;
117-
expect(await getByTestId(element, 'prev')).to.not.exist;
118-
expect(await getByTestId(element, 'last')).to.not.exist;
119-
expect(await getByTestId(element, 'next')).to.not.exist;
106+
buttons[1].click();
107+
await element.requestUpdate('__page');
108+
expect(pageElement.href).to.equal('https://demo.api/hapi/coupon_codes?limit=50&offset=50');
109+
expect(buttons[0]).to.not.have.attribute('disabled');
110+
expect(buttons[1]).to.have.attribute('disabled');
120111
});
121112

122-
it('hides all buttons if collection length is less than limit', async () => {
113+
it('renders complex pagination with overflow', async () => {
123114
const router = createRouter();
124-
const handle = (evt: FetchEvent) => router.handleEvent(evt);
125-
const element = await fixture(html`
126-
<foxy-pagination first="https://demo.api/hapi/transactions">
127-
<test-page-element @fetch=${handle}></test-page-element>
115+
const element = await fixture<Pagination>(html`
116+
<foxy-pagination first="https://demo.api/hapi/coupon_codes?limit=10">
117+
<test-page-element @fetch=${(evt: FetchEvent) => router.handleEvent(evt)}>
118+
</test-page-element>
128119
</foxy-pagination>
129120
`);
130121

131-
const page = element.firstElementChild as NucleonElement<TestData>;
132-
await waitUntil(() => page.in('idle'));
122+
const pageElement = element.firstElementChild as NucleonElement<TestData>;
123+
await waitUntil(() => pageElement.in('idle'));
133124

134-
expect(await getByTestId(element, 'first')).to.not.exist;
135-
expect(await getByTestId(element, 'prev')).to.not.exist;
136-
expect(await getByTestId(element, 'last')).to.not.exist;
137-
expect(await getByTestId(element, 'next')).to.not.exist;
138-
});
125+
const buttons = await getByTestClass(element, 'page-link');
126+
expect(buttons).to.have.length(7);
127+
expect(buttons[0].textContent?.trim()).to.equal('1');
128+
expect(buttons[1].textContent?.trim()).to.equal('2');
129+
expect(buttons[2].textContent?.trim()).to.equal('3');
130+
expect(buttons[3].textContent?.trim()).to.equal('4');
131+
expect(buttons[4].textContent?.trim()).to.equal('5');
132+
expect(buttons[5].textContent?.trim()).to.equal('...');
133+
expect(buttons[6].textContent?.trim()).to.equal('10');
139134

140-
it('disables all buttons when disabled is true', async () => {
141-
const router = createRouter();
142-
const handle = (evt: FetchEvent) => router.handleEvent(evt);
143-
const element = await fixture(html`
144-
<foxy-pagination first="https://demo.api/hapi/coupon_codes" disabled>
145-
<test-page-element @fetch=${handle}></test-page-element>
146-
</foxy-pagination>
147-
`);
135+
const dialog = element.renderRoot.querySelector('dialog');
136+
expect(dialog).to.not.have.attribute('open');
148137

149-
const page = element.firstElementChild as NucleonElement<TestData>;
150-
await waitUntil(() => page.in({ idle: 'snapshot' }));
151-
152-
expect(await getByTestId(element, 'first')).to.have.attribute('disabled');
153-
expect(await getByTestId(element, 'prev')).to.have.attribute('disabled');
154-
expect(await getByTestId(element, 'last')).to.have.attribute('disabled');
155-
expect(await getByTestId(element, 'next')).to.have.attribute('disabled');
138+
buttons[5].click();
139+
expect(dialog).to.have.attribute('open');
156140
});
157141

158-
it('enables all buttons when navigation is available in any direction', async () => {
142+
it('renders Jump To dialog', async () => {
159143
const router = createRouter();
160-
const handle = (evt: FetchEvent) => router.handleEvent(evt);
161-
const element = await fixture(html`
162-
<foxy-pagination first="https://demo.api/hapi/coupon_codes?limit=1&offset=2">
163-
<test-page-element @fetch=${handle}></test-page-element>
144+
const element = await fixture<Pagination>(html`
145+
<foxy-pagination first="https://demo.api/hapi/coupon_codes?limit=10">
146+
<test-page-element @fetch=${(evt: FetchEvent) => router.handleEvent(evt)}>
147+
</test-page-element>
164148
</foxy-pagination>
165149
`);
166150

167-
const page = element.firstElementChild as NucleonElement<TestData>;
168-
await waitUntil(() => page.in({ idle: 'snapshot' }));
169-
170-
expect(await getByTestId(element, 'first')).to.not.have.attribute('disabled');
171-
expect(await getByTestId(element, 'prev')).to.not.have.attribute('disabled');
172-
expect(await getByTestId(element, 'last')).to.not.have.attribute('disabled');
173-
expect(await getByTestId(element, 'next')).to.not.have.attribute('disabled');
151+
const pageElement = element.firstElementChild as NucleonElement<TestData>;
152+
await waitUntil(() => pageElement.in('idle'));
153+
const dialog = element.renderRoot.querySelector('dialog');
154+
const input = dialog?.querySelector<InternalNumberControl>('foxy-internal-number-control');
155+
156+
expect(input).to.exist;
157+
expect(input).to.have.attribute('placeholder', '1');
158+
expect(input).to.have.attribute('helper-text', '');
159+
expect(input).to.have.attribute('label', 'page_number');
160+
expect(input).to.have.attribute('infer', '');
161+
expect(input).to.have.attribute('step', '1');
162+
expect(input).to.have.attribute('min', '1');
163+
expect(input).to.have.attribute('max', '10');
164+
expect(input?.getValue()).to.equal(1);
165+
166+
dialog?.showModal();
167+
input?.setValue(7);
168+
input?.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter' }));
169+
await element.requestUpdate('__page');
170+
expect(pageElement.href).to.equal('https://demo.api/hapi/coupon_codes?limit=10&offset=60');
171+
expect(dialog).to.not.have.attribute('open');
172+
173+
dialog?.showModal();
174+
input?.setValue(8);
175+
const jumpLabel = element.renderRoot.querySelector('foxy-i18n[infer=""][key="jump"]');
176+
const jumpButton = jumpLabel?.closest('vaadin-button');
177+
jumpButton?.click();
178+
await element.requestUpdate('__page');
179+
expect(pageElement.href).to.equal('https://demo.api/hapi/coupon_codes?limit=10&offset=70');
180+
expect(dialog).to.not.have.attribute('open');
174181
});
175182

176-
it('renders current page in a label', async () => {
183+
it('disables controls when disabled', async () => {
177184
const router = createRouter();
178-
const handle = (evt: FetchEvent) => router.handleEvent(evt);
179-
const element = await fixture(html`
180-
<foxy-pagination
181-
first="https://demo.api/hapi/coupon_codes?limit=2&offset=2"
182-
lang="es"
183-
ns="foo"
184-
>
185-
<test-page-element @fetch=${handle}></test-page-element>
185+
const element = await fixture<Pagination>(html`
186+
<foxy-pagination first="https://demo.api/hapi/coupon_codes?limit=50" disabled>
187+
<test-page-element @fetch=${(evt: FetchEvent) => router.handleEvent(evt)}>
188+
</test-page-element>
186189
</foxy-pagination>
187190
`);
188191

189-
const page = element.firstElementChild as NucleonElement<TestData>;
190-
await waitUntil(() => page.in({ idle: 'snapshot' }));
191-
const label = await getByKey(element, 'pagination');
192-
193-
expect(label).to.have.attribute('ns', 'foo');
194-
expect(label).to.have.attribute('lang', 'es');
195-
expect(label).to.have.attribute(
196-
'options',
197-
JSON.stringify({
198-
total: page.data?.total_items,
199-
from: 3,
200-
to: 4,
201-
})
202-
);
192+
const pageElement = element.firstElementChild as NucleonElement<TestData>;
193+
await waitUntil(() => pageElement.in('idle'));
194+
195+
const buttons = await getByTestClass(element, 'page-link');
196+
const select = element.renderRoot.querySelector<HTMLSelectElement>('select');
197+
198+
expect(buttons[0]).to.have.attribute('disabled');
199+
expect(buttons[1]).to.have.attribute('disabled');
200+
expect(select).to.have.attribute('disabled');
203201
});
204202
});

0 commit comments

Comments
 (0)