feat(topbar): «Что нового» button + 2026-05-12 state.md update

This commit is contained in:
Александр Зимин
2026-05-12 17:05:24 +00:00
parent 58dd871808
commit a34c6d4c82
21 changed files with 1853 additions and 8 deletions
@@ -0,0 +1,133 @@
import { describe, it, expect } from 'vitest'
import { parseChangelog, isVersionNewer } from './useChangelog'
describe('parseChangelog', () => {
it('parses single version с features section', () => {
const raw = `# Release Notes
## [2.14.0](https://example.com/compare/v2.13.0...v2.14.0) (2026-05-12)
### ✨ Features
* **webhook:** time-series histogram stats endpoint ([5479142](https://example.com/commit/5479142))
`
const entries = parseChangelog(raw)
expect(entries).toHaveLength(1)
expect(entries[0].version).toBe('2.14.0')
expect(entries[0].date).toBe('2026-05-12')
expect(entries[0].compareUrl).toContain('compare/v2.13.0...v2.14.0')
expect(entries[0].sections).toHaveLength(1)
expect(entries[0].sections[0].emoji).toBe('✨')
expect(entries[0].sections[0].title).toBe('Features')
expect(entries[0].sections[0].items).toHaveLength(1)
expect(entries[0].sections[0].items[0].scope).toBe('webhook')
expect(entries[0].sections[0].items[0].description).toBe('time-series histogram stats endpoint')
expect(entries[0].sections[0].items[0].commit).toBe('5479142')
expect(entries[0].sections[0].items[0].commitUrl).toContain('/commit/5479142')
})
it('parses multiple versions newest-first', () => {
const raw = `## [2.14.0](url1) (2026-05-12)
### ✨ Features
* **a:** first ([abc1234](url2))
## [2.13.0](url3) (2026-05-11)
### 🐛 Fixes
* **b:** second ([def5678](url4))
`
const entries = parseChangelog(raw)
expect(entries.map((e) => e.version)).toEqual(['2.14.0', '2.13.0'])
})
it('handles section без emoji', () => {
const raw = `## [1.0.0](url) (2026-01-01)
### Features
* first feature
`
const entries = parseChangelog(raw)
expect(entries[0].sections[0].emoji).toBeUndefined()
expect(entries[0].sections[0].title).toBe('Features')
})
it('handles item без scope', () => {
const raw = `## [1.0.0](url) (2026-01-01)
### Features
* description without scope
* another one ([abc1234](url2))
`
const entries = parseChangelog(raw)
const items = entries[0].sections[0].items
expect(items[0].scope).toBeUndefined()
expect(items[0].description).toBe('description without scope')
expect(items[1].scope).toBeUndefined()
expect(items[1].description).toBe('another one')
expect(items[1].commit).toBe('abc1234')
})
it('handles empty changelog', () => {
expect(parseChangelog('')).toEqual([])
expect(parseChangelog('# Just a title\n\nNo versions yet.')).toEqual([])
})
it('handles version без date', () => {
const raw = `## [1.0.0](url)
### Features
* foo
`
const entries = parseChangelog(raw)
expect(entries[0].version).toBe('1.0.0')
expect(entries[0].date).toBeUndefined()
})
it('handles version с multiple sections', () => {
const raw = `## [2.10.0](url) (2026-05-12)
### ✨ Features
* **timetravel:** new tab
### 🐛 Fixes
* **ux:** friendly errors
`
const entries = parseChangelog(raw)
expect(entries[0].sections).toHaveLength(2)
expect(entries[0].sections[0].title).toBe('Features')
expect(entries[0].sections[1].title).toBe('Fixes')
})
})
describe('isVersionNewer', () => {
it('returns true когда seen is null', () => {
expect(isVersionNewer('2.14.0', null)).toBe(true)
})
it('compares major.minor.patch correctly', () => {
expect(isVersionNewer('2.14.0', '2.13.0')).toBe(true)
expect(isVersionNewer('2.14.1', '2.14.0')).toBe(true)
expect(isVersionNewer('3.0.0', '2.99.99')).toBe(true)
expect(isVersionNewer('2.13.0', '2.14.0')).toBe(false)
expect(isVersionNewer('2.14.0', '2.14.0')).toBe(false)
})
it('strips v prefix', () => {
expect(isVersionNewer('v2.14.0', '2.13.0')).toBe(true)
expect(isVersionNewer('2.14.0', 'v2.13.0')).toBe(true)
})
it('returns false для unparseable formats (treat as not newer)', () => {
expect(isVersionNewer('dev', '2.14.0')).toBe(false)
expect(isVersionNewer('2.14.0', 'dev')).toBe(false)
expect(isVersionNewer('local', 'unknown')).toBe(false)
})
})