fix: implement fetch generation counter to handle concurrent refreshes in ScrollingList
Some checks failed
Chore App Build, Test, and Push Docker Images / build-and-push (push) Has been cancelled

- Added a fetch generation counter to the fetchItems method to discard stale results from concurrent fetches.
- Updated the loading state management to ensure it only updates if the fetch is the latest.
- Enhanced the refresh method to prevent stale data from being rendered when multiple refreshes occur.
- Added a test case to verify that stale fetches are discarded correctly when concurrent refreshes happen.
- Fixed CSS for mobile banners to prevent overflow and adjusted font sizes for better visibility.
- Resolved issues with task icons disappearing when extending time on overdue chores by ensuring only one fetch is active at a time.
This commit is contained in:
2026-03-25 15:30:00 -04:00
parent f64311689b
commit 359c170b27
15 changed files with 166 additions and 35 deletions

View File

@@ -66,7 +66,7 @@ test.describe('Chore assignment', () => {
await expect(page.getByRole('button', { name: 'Assign Chores' })).toBeVisible()
await page.getByRole('button', { name: 'Assign Chores' }).click()
await page.waitForURL(new RegExp(`/parent/${childId}/assign-chores$`))
await page.waitForURL(new RegExp(`/parent/${childId}/assign-chores(\\?|$)`))
await expect(page.getByRole('heading', { name: 'Assign Chores' })).toBeVisible()
@@ -83,7 +83,7 @@ test.describe('Chore assignment', () => {
test('Select chores and submit — items appear in ParentView chores section', async ({ page }) => {
await page.goto(`/parent/${childId}`)
await page.getByRole('button', { name: 'Assign Chores' }).click()
await page.waitForURL(new RegExp(`/parent/${childId}/assign-chores$`))
await page.waitForURL(new RegExp(`/parent/${childId}/assign-chores(\\?|$)`))
await expect(page.getByRole('heading', { name: 'Assign Chores' })).toBeVisible()
// Select two chores
@@ -126,7 +126,7 @@ test.describe('Chore assignment', () => {
test('Uncheck all chores and submit — items are removed from ParentView', async ({ page }) => {
await page.goto(`/parent/${childId}`)
await page.getByRole('button', { name: 'Assign Chores' }).click()
await page.waitForURL(new RegExp(`/parent/${childId}/assign-chores$`))
await page.waitForURL(new RegExp(`/parent/${childId}/assign-chores(\\?|$)`))
await expect(page.getByRole('heading', { name: 'Assign Chores' })).toBeVisible()
// Uncheck the two previously assigned chores
@@ -151,7 +151,7 @@ test.describe('Chore assignment', () => {
test('Cancel does not persist selection changes', async ({ page }) => {
await page.goto(`/parent/${childId}`)
await page.getByRole('button', { name: 'Assign Chores' }).click()
await page.waitForURL(new RegExp(`/parent/${childId}/assign-chores$`))
await page.waitForURL(new RegExp(`/parent/${childId}/assign-chores(\\?|$)`))
await expect(page.getByRole('heading', { name: 'Assign Chores' })).toBeVisible()
// Check an item

View File

@@ -56,7 +56,7 @@ test.describe('Kindness act assignment', () => {
await expect(page.getByRole('button', { name: 'Assign Kindness Acts' })).toBeVisible()
await page.getByRole('button', { name: 'Assign Kindness Acts' }).click()
await page.waitForURL(new RegExp(`/parent/${childId}/assign-kindness$`))
await page.waitForURL(new RegExp(`/parent/${childId}/assign-kindness(\\?|$)`))
await expect(page.getByRole('heading', { name: 'Assign Kindness Acts' })).toBeVisible()
@@ -72,7 +72,7 @@ test.describe('Kindness act assignment', () => {
test('Select a kindness act and submit — item appears in ParentView', async ({ page }) => {
await page.goto(`/parent/${childId}`)
await page.getByRole('button', { name: 'Assign Kindness Acts' }).click()
await page.waitForURL(new RegExp(`/parent/${childId}/assign-kindness$`))
await page.waitForURL(new RegExp(`/parent/${childId}/assign-kindness(\\?|$)`))
await expect(page.getByRole('heading', { name: 'Assign Kindness Acts' })).toBeVisible()
await page.getByText(KIND1_NAME, { exact: true }).click()
@@ -101,7 +101,7 @@ test.describe('Kindness act assignment', () => {
}) => {
await page.goto(`/parent/${childId}`)
await page.getByRole('button', { name: 'Assign Kindness Acts' }).click()
await page.waitForURL(new RegExp(`/parent/${childId}/assign-kindness$`))
await page.waitForURL(new RegExp(`/parent/${childId}/assign-kindness(\\?|$)`))
await expect(page.getByRole('heading', { name: 'Assign Kindness Acts' })).toBeVisible()
// Uncheck the previously assigned item
@@ -120,7 +120,7 @@ test.describe('Kindness act assignment', () => {
test('Cancel does not persist selection changes', async ({ page }) => {
await page.goto(`/parent/${childId}`)
await page.getByRole('button', { name: 'Assign Kindness Acts' }).click()
await page.waitForURL(new RegExp(`/parent/${childId}/assign-kindness$`))
await page.waitForURL(new RegExp(`/parent/${childId}/assign-kindness(\\?|$)`))
await expect(page.getByRole('heading', { name: 'Assign Kindness Acts' })).toBeVisible()
// Check the item

View File

@@ -66,7 +66,7 @@ test.describe('Penalty assignment', () => {
await expect(page.getByRole('button', { name: 'Assign Penalties' })).toBeVisible()
await page.getByRole('button', { name: 'Assign Penalties' }).click()
await page.waitForURL(new RegExp(`/parent/${childId}/assign-penalties$`))
await page.waitForURL(new RegExp(`/parent/${childId}/assign-penalties(\\?|$)`))
await expect(page.getByRole('heading', { name: 'Assign Penalties' })).toBeVisible()
@@ -85,7 +85,7 @@ test.describe('Penalty assignment', () => {
}) => {
await page.goto(`/parent/${childId}`)
await page.getByRole('button', { name: 'Assign Penalties' }).click()
await page.waitForURL(new RegExp(`/parent/${childId}/assign-penalties$`))
await page.waitForURL(new RegExp(`/parent/${childId}/assign-penalties(\\?|$)`))
await expect(page.getByRole('heading', { name: 'Assign Penalties' })).toBeVisible()
// Select two penalties
@@ -128,7 +128,7 @@ test.describe('Penalty assignment', () => {
test('Uncheck all penalties and submit — items are removed from ParentView', async ({ page }) => {
await page.goto(`/parent/${childId}`)
await page.getByRole('button', { name: 'Assign Penalties' }).click()
await page.waitForURL(new RegExp(`/parent/${childId}/assign-penalties$`))
await page.waitForURL(new RegExp(`/parent/${childId}/assign-penalties(\\?|$)`))
await expect(page.getByRole('heading', { name: 'Assign Penalties' })).toBeVisible()
// Uncheck the previously assigned penalties
@@ -153,7 +153,7 @@ test.describe('Penalty assignment', () => {
test('Cancel does not persist selection changes', async ({ page }) => {
await page.goto(`/parent/${childId}`)
await page.getByRole('button', { name: 'Assign Penalties' }).click()
await page.waitForURL(new RegExp(`/parent/${childId}/assign-penalties$`))
await page.waitForURL(new RegExp(`/parent/${childId}/assign-penalties(\\?|$)`))
await expect(page.getByRole('heading', { name: 'Assign Penalties' })).toBeVisible()
// Check an item

View File

@@ -62,7 +62,7 @@ test.describe('Reward assignment', () => {
await expect(page.getByRole('button', { name: 'Assign Rewards' })).toBeVisible()
await page.getByRole('button', { name: 'Assign Rewards' }).click()
await page.waitForURL(new RegExp(`/parent/${childId}/assign-rewards$`))
await page.waitForURL(new RegExp(`/parent/${childId}/assign-rewards(\\?|$)`))
await expect(page.getByRole('heading', { name: 'Assign Rewards' })).toBeVisible()
@@ -81,7 +81,7 @@ test.describe('Reward assignment', () => {
}) => {
await page.goto(`/parent/${childId}`)
await page.getByRole('button', { name: 'Assign Rewards' }).click()
await page.waitForURL(new RegExp(`/parent/${childId}/assign-rewards$`))
await page.waitForURL(new RegExp(`/parent/${childId}/assign-rewards(\\?|$)`))
await expect(page.getByRole('heading', { name: 'Assign Rewards' })).toBeVisible()
// Select two rewards
@@ -124,7 +124,7 @@ test.describe('Reward assignment', () => {
test('Uncheck all rewards and submit — items are removed from ParentView', async ({ page }) => {
await page.goto(`/parent/${childId}`)
await page.getByRole('button', { name: 'Assign Rewards' }).click()
await page.waitForURL(new RegExp(`/parent/${childId}/assign-rewards$`))
await page.waitForURL(new RegExp(`/parent/${childId}/assign-rewards(\\?|$)`))
await expect(page.getByRole('heading', { name: 'Assign Rewards' })).toBeVisible()
// Uncheck the previously assigned rewards
@@ -149,7 +149,7 @@ test.describe('Reward assignment', () => {
test('Cancel does not persist selection changes', async ({ page }) => {
await page.goto(`/parent/${childId}`)
await page.getByRole('button', { name: 'Assign Rewards' }).click()
await page.waitForURL(new RegExp(`/parent/${childId}/assign-rewards$`))
await page.waitForURL(new RegExp(`/parent/${childId}/assign-rewards(\\?|$)`))
await expect(page.getByRole('heading', { name: 'Assign Rewards' })).toBeVisible()
// Check an item