diff --git a/core/src/components.d.ts b/core/src/components.d.ts index 9c14861ef13..37223c4f77a 100644 --- a/core/src/components.d.ts +++ b/core/src/components.d.ts @@ -8046,7 +8046,7 @@ declare namespace LocalJSX { */ "onIonRefresh"?: (event: IonRefresherCustomEvent) => void; /** - * Emitted when the user begins to start pulling down. TODO(FW-7044): Remove this in a major release + * Emitted when the user begins to start pulling down. * @deprecated Use `ionPullStart` instead. */ "onIonStart"?: (event: IonRefresherCustomEvent) => void; diff --git a/core/src/components/refresher/refresher.tsx b/core/src/components/refresher/refresher.tsx index 2b933bc5f77..9d7c6a7ad06 100644 --- a/core/src/components/refresher/refresher.tsx +++ b/core/src/components/refresher/refresher.tsx @@ -141,9 +141,9 @@ export class Refresher implements ComponentInterface { */ @Event() ionPull!: EventEmitter; + // TODO(FW-7044): Remove this in a major release /** * Emitted when the user begins to start pulling down. - * TODO(FW-7044): Remove this in a major release * * @deprecated Use `ionPullStart` instead. */ diff --git a/packages/angular/src/directives/proxies.ts b/packages/angular/src/directives/proxies.ts index 3d17a936026..1c78b120d9d 100644 --- a/packages/angular/src/directives/proxies.ts +++ b/packages/angular/src/directives/proxies.ts @@ -1831,8 +1831,7 @@ called when the async operation has completed. */ ionPull: EventEmitter>; /** - * Emitted when the user begins to start pulling down. -TODO(FW-7044): Remove this in a major release @deprecated Use `ionPullStart` instead. + * Emitted when the user begins to start pulling down. @deprecated Use `ionPullStart` instead. */ ionStart: EventEmitter>; /** diff --git a/packages/angular/src/index.ts b/packages/angular/src/index.ts index 990108e3286..86422fdd861 100644 --- a/packages/angular/src/index.ts +++ b/packages/angular/src/index.ts @@ -114,6 +114,8 @@ export { RangeKnobMoveEndEventDetail, RefresherCustomEvent, RefresherEventDetail, + RefresherPullEndCustomEvent, + RefresherPullEndEventDetail, ReorderMoveCustomEvent, ReorderMoveEventDetail, ReorderEndCustomEvent, diff --git a/packages/angular/standalone/src/directives/proxies.ts b/packages/angular/standalone/src/directives/proxies.ts index d92609b5501..eae6fdb8840 100644 --- a/packages/angular/standalone/src/directives/proxies.ts +++ b/packages/angular/standalone/src/directives/proxies.ts @@ -1685,8 +1685,7 @@ called when the async operation has completed. */ ionPull: EventEmitter>; /** - * Emitted when the user begins to start pulling down. -TODO(FW-7044): Remove this in a major release @deprecated Use `ionPullStart` instead. + * Emitted when the user begins to start pulling down. @deprecated Use `ionPullStart` instead. */ ionStart: EventEmitter>; /** diff --git a/packages/angular/standalone/src/index.ts b/packages/angular/standalone/src/index.ts index 06b8e7f1796..a4ac729cc7e 100644 --- a/packages/angular/standalone/src/index.ts +++ b/packages/angular/standalone/src/index.ts @@ -112,6 +112,8 @@ export { RangeKnobMoveEndEventDetail, RefresherCustomEvent, RefresherEventDetail, + RefresherPullEndCustomEvent, + RefresherPullEndEventDetail, ReorderMoveCustomEvent, ReorderMoveEventDetail, ReorderEndCustomEvent, diff --git a/packages/angular/test/base/e2e/src/standalone/refresher.spec.ts b/packages/angular/test/base/e2e/src/standalone/refresher.spec.ts new file mode 100644 index 00000000000..18109696c83 --- /dev/null +++ b/packages/angular/test/base/e2e/src/standalone/refresher.spec.ts @@ -0,0 +1,50 @@ +import { expect, test } from '@playwright/test'; + +/** + * Simulates a pull-to-refresh gesture by dragging from the top of + * the content element downward with intermediate steps so the + * gesture recognizer detects the movement. + */ +const pullDown = async (page: import('@playwright/test').Page, distance: number) => { + const content = page.locator('ion-content'); + const box = await content.boundingBox(); + if (!box) throw new Error('ion-content not visible'); + + const startX = box.x + box.width / 2; + const startY = box.y + 30; + + await page.mouse.move(startX, startY); + await page.mouse.down(); + await page.mouse.move(startX, startY + distance, { steps: 20 }); + await page.mouse.up(); +}; + +test.describe('refresher: angular standalone', () => { + test.beforeEach(async ({ page }) => { + await page.goto('/standalone/refresher'); + }); + + test('should emit ionPullStart and ionPullEnd with cancel reason', async ({ page }) => { + // Small drag that doesn't reach the refresh threshold + await pullDown(page, 60); + + await page.waitForTimeout(500); + + await expect(page.locator('#pull-start-count')).toHaveText('1'); + await expect(page.locator('#refresh-count')).toHaveText('0'); + await expect(page.locator('#pull-end-count')).toHaveText('1'); + await expect(page.locator('#pull-end-reason')).toHaveText('cancel'); + }); + + test('should emit ionPullStart, ionRefresh, and ionPullEnd with complete reason', async ({ page }) => { + // Large drag past the refresh threshold + await pullDown(page, 300); + + await page.waitForTimeout(1000); + + await expect(page.locator('#pull-start-count')).toHaveText('1'); + await expect(page.locator('#refresh-count')).toHaveText('1'); + await expect(page.locator('#pull-end-count')).toHaveText('1'); + await expect(page.locator('#pull-end-reason')).toHaveText('complete'); + }); +}); diff --git a/packages/angular/test/base/src/app/standalone/app-standalone/app.routes.ts b/packages/angular/test/base/src/app/standalone/app-standalone/app.routes.ts index a12903f57d3..3f9f82933f6 100644 --- a/packages/angular/test/base/src/app/standalone/app-standalone/app.routes.ts +++ b/packages/angular/test/base/src/app/standalone/app-standalone/app.routes.ts @@ -32,6 +32,7 @@ export const routes: Routes = [ { path: 'providers', loadComponent: () => import('../providers/providers.component').then(c => c.ProvidersComponent) }, { path: 'overlay-controllers', loadComponent: () => import('../overlay-controllers/overlay-controllers.component').then(c => c.OverlayControllersComponent) }, { path: 'button', loadComponent: () => import('../button/button.component').then(c => c.ButtonComponent) }, + { path: 'refresher', loadComponent: () => import('../refresher/refresher.component').then(c => c.RefresherComponent) }, { path: 'reorder-group', loadComponent: () => import('../reorder-group/reorder-group.component').then(c => c.ReorderGroupComponent) }, { path: 'icon', loadComponent: () => import('../icon/icon.component').then(c => c.IconComponent) }, { path: 'split-pane', redirectTo: '/standalone/split-pane/inbox', pathMatch: 'full' }, diff --git a/packages/angular/test/base/src/app/standalone/home-page/home-page.component.html b/packages/angular/test/base/src/app/standalone/home-page/home-page.component.html index 9bc81f2433e..641018e757c 100644 --- a/packages/angular/test/base/src/app/standalone/home-page/home-page.component.html +++ b/packages/angular/test/base/src/app/standalone/home-page/home-page.component.html @@ -33,6 +33,11 @@ Inputs Test + + + Refresher Test + + Reorder Group Test diff --git a/packages/angular/test/base/src/app/standalone/refresher/refresher.component.ts b/packages/angular/test/base/src/app/standalone/refresher/refresher.component.ts new file mode 100644 index 00000000000..e2579e978f2 --- /dev/null +++ b/packages/angular/test/base/src/app/standalone/refresher/refresher.component.ts @@ -0,0 +1,69 @@ +import { Component } from "@angular/core"; +import { IonContent, IonHeader, IonItem, IonLabel, IonList, IonRefresher, IonRefresherContent, IonTitle, IonToolbar } from '@ionic/angular/standalone'; +import { RefresherCustomEvent, RefresherPullEndCustomEvent } from "@ionic/angular"; + +@Component({ + selector: 'app-refresher', + template: ` + + + Refresher Test + + + + + + + + + + + ionPullStart count: {{ pullStartCount }} + + + + + ionRefresh count: {{ refreshCount }} + + + + + ionPullEnd count: {{ pullEndCount }} + + + + + ionPullEnd reason: {{ pullEndReason }} + + + + + `, + standalone: true, + imports: [IonContent, IonHeader, IonItem, IonLabel, IonList, IonRefresher, IonRefresherContent, IonTitle, IonToolbar] +}) +export class RefresherComponent { + pullStartCount = 0; + refreshCount = 0; + pullEndCount = 0; + pullEndReason = ''; + + onPullStart() { + this.pullStartCount++; + } + + onRefresh(event: RefresherCustomEvent) { + this.refreshCount++; + event.target.complete(); + } + + onPullEnd(event: RefresherPullEndCustomEvent) { + this.pullEndCount++; + this.pullEndReason = event.detail.reason; + } +}