test(04-07): add failing collation regression test (LIST-03)
- Seed items with ranks 'a0' and 'a1', drag second to top via rank 'Zz' - Assert 'Zz' < 'a0' is true in JS (documents uppercase-before-lowercase intent) - GET /api/lists/:id/items must return Zz-ranked item at index 0 - Fails now because MariaDB utf8mb4_uca1400_ai_ci sorts 'Zz' after 'a0' - Will pass once rank column gets COLLATE utf8mb4_bin via migration
This commit is contained in:
@@ -1037,4 +1037,38 @@ describe('PATCH /api/list-items/:id { position } — reorder ordering (LIST-03,
|
|||||||
const res = await app.request(jsonRequest('PATCH', `/api/list-items/${itemId}`, { position: 'a1', checked: true }))
|
const res = await app.request(jsonRequest('PATCH', `/api/list-items/${itemId}`, { position: 'a1', checked: true }))
|
||||||
expect(res.status).toBe(400)
|
expect(res.status).toBe(400)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('drag-to-top: uppercase-prefixed rank sorts above lowercase ranks (LIST-03 collation regression)', async () => {
|
||||||
|
const ownerId = await seedUser('reorder-collation')
|
||||||
|
currentDevUserId = ownerId
|
||||||
|
const listId = await seedList(ownerId, 'Collation Test', false)
|
||||||
|
|
||||||
|
// Seed two active items: item1 has lowercase rank 'a0', item2 has rank 'a1'
|
||||||
|
const id1 = await seedItem(listId, 'first', 'a0')
|
||||||
|
const id2 = await seedItem(listId, 'second', 'a1')
|
||||||
|
|
||||||
|
// JS string comparison: 'Zz' < 'a0' is true (uppercase sorts before lowercase in JS/Unicode)
|
||||||
|
// This is what fractional-indexing produces for generateKeyBetween(null, 'a0') — a drag-to-top
|
||||||
|
expect('Zz' < 'a0').toBe(true)
|
||||||
|
|
||||||
|
// Drag item2 to top by assigning it the uppercase-prefixed rank 'Zz'
|
||||||
|
const app = await getApp()
|
||||||
|
const patchRes = await app.request(jsonRequest('PATCH', `/api/list-items/${id2}`, { position: 'Zz' }))
|
||||||
|
expect(patchRes.status).toBe(200)
|
||||||
|
const patchBody = await patchRes.json() as { rank: string }
|
||||||
|
expect(patchBody.rank).toBe('Zz')
|
||||||
|
|
||||||
|
// GET /api/lists/:listId/items — the dragged item (rank 'Zz') MUST be returned first (index 0)
|
||||||
|
// This exercises the real DB ORDER BY rank. Without utf8mb4_bin collation, MariaDB's
|
||||||
|
// case-insensitive default collation sorts 'Zz' AFTER 'a0', placing the item last.
|
||||||
|
const getRes = await app.request(`/api/lists/${listId}/items`)
|
||||||
|
expect(getRes.status).toBe(200)
|
||||||
|
const getBody = await getRes.json() as { items: Array<{ id: number; rank: string }> }
|
||||||
|
expect(getBody.items).toHaveLength(2)
|
||||||
|
// item2 (rank 'Zz') must be first — drag-to-top persists
|
||||||
|
expect(getBody.items[0].id).toBe(id2)
|
||||||
|
expect(getBody.items[0].rank).toBe('Zz')
|
||||||
|
// item1 (rank 'a0') must be second
|
||||||
|
expect(getBody.items[1].id).toBe(id1)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user