- All 8 home page sections: Hero, Locations slider, WhyParents accordion, Birthday pricing cards, Video, Gallery, Reviews slider, News - UI components: NavLink, BtnPrimary, BtnGradient, BtnDetails, AccordionItem - Layout: sticky Header (NavLink + BtnPrimary), Footer with logo - Figma Code Connect: 5 components published (.figma.tsx + figma.config.json) - Public assets: all Figma images and SVGs exported - Pages: /kvytky, /lokatsii, /blog, /dni-narodzhennia, /grupovi-vidviduvannia - Tests: Vitest unit/api suites, Playwright e2e screenshots - Payload CMS: blocks, collections, seed data updates - Hero negative-margin to extend behind sticky header - Custom Tailwind breakpoints: lg=1440px, xl=1920px - Fix ESLint config: drop FlatCompat, use eslint-config-next flat export - Add tsconfig.tsbuildinfo, test-results/, agentdb.rvf* to .gitignore Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
136 lines
4.5 KiB
TypeScript
136 lines
4.5 KiB
TypeScript
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
|
|
|
const mockGetTariffs = vi.fn()
|
|
const mockPayloadFind = vi.fn()
|
|
const mockPayloadUpdate = vi.fn()
|
|
const mockPayloadCreate = vi.fn()
|
|
const mockGetPayload = vi.fn(() => ({
|
|
find: mockPayloadFind,
|
|
update: mockPayloadUpdate,
|
|
create: mockPayloadCreate,
|
|
}))
|
|
|
|
vi.mock('@/lib/ezy', () => ({ getTariffs: mockGetTariffs }))
|
|
vi.mock('payload', () => ({ getPayload: mockGetPayload }))
|
|
vi.mock('@payload-config', () => ({ default: {} }))
|
|
|
|
let syncTariffs: () => Promise<{ synced: number; created: number; hidden: number }>
|
|
|
|
beforeEach(async () => {
|
|
vi.resetModules()
|
|
mockGetTariffs.mockReset()
|
|
mockPayloadFind.mockReset()
|
|
mockPayloadUpdate.mockReset()
|
|
mockPayloadCreate.mockReset()
|
|
const mod = await import('@/lib/syncTariffs')
|
|
syncTariffs = mod.syncTariffs
|
|
})
|
|
|
|
describe('syncTariffs', () => {
|
|
it('updates existing tariffs and returns correct synced count', async () => {
|
|
mockGetTariffs.mockResolvedValueOnce([
|
|
{ id: 1, name: 'Adult', price: 250 },
|
|
{ id: 2, name: 'Child', price: 150 },
|
|
])
|
|
// per-tariff find calls + final visible-tariffs scan
|
|
mockPayloadFind
|
|
.mockResolvedValueOnce({ docs: [{ id: 'tariff-1', ezy_id: 1 }] })
|
|
.mockResolvedValueOnce({ docs: [{ id: 'tariff-2', ezy_id: 2 }] })
|
|
.mockResolvedValueOnce({ docs: [] })
|
|
mockPayloadUpdate.mockResolvedValue({})
|
|
|
|
const result = await syncTariffs()
|
|
expect(result.synced).toBe(2)
|
|
expect(result.created).toBe(0)
|
|
expect(result.hidden).toBe(0)
|
|
expect(mockPayloadUpdate).toHaveBeenCalledTimes(2)
|
|
})
|
|
|
|
it('creates new tariffs when ezy_id does not exist in DB', async () => {
|
|
mockGetTariffs.mockResolvedValueOnce([
|
|
{ id: 1, name: 'Adult', price: 250 },
|
|
{ id: 2, name: 'Child', price: 150 },
|
|
])
|
|
mockPayloadFind
|
|
.mockResolvedValueOnce({ docs: [] })
|
|
.mockResolvedValueOnce({ docs: [] })
|
|
.mockResolvedValueOnce({ docs: [] })
|
|
mockPayloadCreate.mockResolvedValue({})
|
|
|
|
const result = await syncTariffs()
|
|
expect(result.created).toBe(2)
|
|
expect(result.synced).toBe(0)
|
|
expect(mockPayloadCreate).toHaveBeenCalledTimes(2)
|
|
})
|
|
|
|
it('hides DB tariffs that are no longer present in ezy', async () => {
|
|
mockGetTariffs.mockResolvedValueOnce([{ id: 1, name: 'Adult', price: 250 }])
|
|
mockPayloadFind
|
|
.mockResolvedValueOnce({ docs: [{ id: 'tariff-1', ezy_id: 1 }] })
|
|
// visible scan: id:99 is not in ezy anymore
|
|
.mockResolvedValueOnce({ docs: [{ id: 'tariff-stale', ezy_id: 99 }] })
|
|
mockPayloadUpdate.mockResolvedValue({})
|
|
|
|
const result = await syncTariffs()
|
|
expect(result.hidden).toBe(1)
|
|
expect(mockPayloadUpdate).toHaveBeenCalledWith(
|
|
expect.objectContaining({
|
|
id: 'tariff-stale',
|
|
data: { visible: false },
|
|
})
|
|
)
|
|
})
|
|
|
|
it('returns zero counts when ezy returns an empty array', async () => {
|
|
mockGetTariffs.mockResolvedValueOnce([])
|
|
mockPayloadFind.mockResolvedValueOnce({ docs: [] })
|
|
|
|
const result = await syncTariffs()
|
|
expect(result).toEqual({ synced: 0, created: 0, hidden: 0 })
|
|
})
|
|
|
|
it('propagates error when getTariffs throws', async () => {
|
|
mockGetTariffs.mockRejectedValueOnce(new Error('ezy unavailable'))
|
|
await expect(syncTariffs()).rejects.toThrow('ezy unavailable')
|
|
})
|
|
|
|
it('writes last_synced_name and last_synced_price when updating an existing tariff', async () => {
|
|
mockGetTariffs.mockResolvedValueOnce([{ id: 1, name: 'Updated Adult', price: 300 }])
|
|
mockPayloadFind
|
|
.mockResolvedValueOnce({ docs: [{ id: 'tariff-1', ezy_id: 1 }] })
|
|
.mockResolvedValueOnce({ docs: [] })
|
|
mockPayloadUpdate.mockResolvedValue({})
|
|
|
|
await syncTariffs()
|
|
expect(mockPayloadUpdate).toHaveBeenCalledWith(
|
|
expect.objectContaining({
|
|
collection: 'tariffs',
|
|
id: 'tariff-1',
|
|
data: expect.objectContaining({
|
|
last_synced_name: 'Updated Adult',
|
|
last_synced_price: 300,
|
|
}),
|
|
})
|
|
)
|
|
})
|
|
|
|
it('creates new tariff with category_tag dyno and visible:true', async () => {
|
|
mockGetTariffs.mockResolvedValueOnce([{ id: 5, name: 'VIP', price: 500 }])
|
|
mockPayloadFind
|
|
.mockResolvedValueOnce({ docs: [] })
|
|
.mockResolvedValueOnce({ docs: [] })
|
|
mockPayloadCreate.mockResolvedValue({})
|
|
|
|
await syncTariffs()
|
|
expect(mockPayloadCreate).toHaveBeenCalledWith(
|
|
expect.objectContaining({
|
|
collection: 'tariffs',
|
|
data: expect.objectContaining({
|
|
ezy_id: 5,
|
|
category_tag: 'dyno',
|
|
visible: true,
|
|
}),
|
|
})
|
|
)
|
|
})
|
|
})
|