Skip to content

Commit 5668e1d

Browse files
authored
Release v0.2.2
release: v0.2.2
2 parents cebd16d + 2336ed6 commit 5668e1d

32 files changed

+3468
-728
lines changed

package-lock.json

Lines changed: 2 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "termul-manager",
3-
"version": "0.1.7",
3+
"version": "0.2.2",
44
"description": "Project-aware terminal that treats workspaces as first-class citizens",
55
"main": "./out/main/index.js",
66
"author": {

src/renderer/components/ProjectSidebar.test.tsx

Lines changed: 77 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { describe, it, expect, vi, beforeEach } from 'vitest'
2-
import { render, screen, fireEvent, waitFor } from '@testing-library/react'
2+
import { render, screen, fireEvent, waitFor, within } from '@testing-library/react'
33
import { MemoryRouter } from 'react-router-dom'
44
import { ProjectSidebar } from './ProjectSidebar'
55
import type { Project } from '@/types/project'
@@ -219,6 +219,16 @@ describe('ProjectSidebar', () => {
219219
expect(screen.getByText('Project Two')).toBeInTheDocument()
220220
})
221221

222+
it('should render project avatars with first letter', () => {
223+
renderWithRouter()
224+
225+
const activeProjectsContainer = screen.getByTestId('active-projects-container')
226+
const avatars = within(activeProjectsContainer).getAllByTestId('project-avatar-letter')
227+
const letters = avatars.map((avatar) => avatar.textContent)
228+
229+
expect(letters).toStrictEqual(['P', 'P'])
230+
})
231+
222232
it('should call onSelectProject when project is clicked', () => {
223233
const onSelectProject = vi.fn()
224234
renderWithRouter({ onSelectProject })
@@ -228,11 +238,24 @@ describe('ProjectSidebar', () => {
228238
expect(onSelectProject).toHaveBeenCalledWith('2')
229239
})
230240

231-
it('should call onNewProject when New Project is clicked', () => {
241+
it('should call onNewProject when header + button is clicked', () => {
232242
const onNewProject = vi.fn()
233243
renderWithRouter({ onNewProject })
234244

235-
fireEvent.click(screen.getByText('New Project'))
245+
// Use data-testid for robust button selection
246+
const headerButton = screen.getByTestId('header-new-project')
247+
fireEvent.click(headerButton)
248+
249+
expect(onNewProject).toHaveBeenCalled()
250+
})
251+
252+
it('should call onNewProject when bottom + button is clicked', () => {
253+
const onNewProject = vi.fn()
254+
renderWithRouter({ onNewProject })
255+
256+
// Use data-testid for robust button selection
257+
const bottomButton = screen.getByTestId('bottom-new-project')
258+
fireEvent.click(bottomButton)
236259

237260
expect(onNewProject).toHaveBeenCalled()
238261
})
@@ -242,6 +265,57 @@ describe('ProjectSidebar', () => {
242265

243266
expect(screen.getByText('No projects yet')).toBeInTheDocument()
244267
})
268+
269+
it('should not render removed navigation items', () => {
270+
renderWithRouter()
271+
272+
// These items were removed from the sidebar
273+
expect(screen.queryByText('Workspace')).not.toBeInTheDocument()
274+
expect(screen.queryByText('Snapshots')).not.toBeInTheDocument()
275+
expect(screen.queryByText('Settings')).not.toBeInTheDocument()
276+
expect(screen.queryByText('Preferences')).not.toBeInTheDocument()
277+
})
278+
279+
it('should not render removed action items', () => {
280+
renderWithRouter()
281+
282+
// These actions were removed from the sidebar
283+
expect(screen.queryByText('Scan Directories')).not.toBeInTheDocument()
284+
expect(screen.queryByText('Import Config')).not.toBeInTheDocument()
285+
})
286+
287+
it('should handle project with empty name gracefully', () => {
288+
const projectsWithEmptyName: Project[] = [
289+
{ id: '1', name: '', color: 'blue', gitBranch: 'main' }
290+
]
291+
renderWithRouter({ projects: projectsWithEmptyName })
292+
293+
// Should show fallback character '?' for empty name
294+
const avatar = screen.getByTestId('project-avatar-letter')
295+
expect(avatar).toHaveTextContent('?')
296+
})
297+
298+
it('should extract first alphabetic character for emoji project names', () => {
299+
const projectsWithEmoji: Project[] = [
300+
{ id: '1', name: '🚀Rocket', color: 'blue', gitBranch: 'main' }
301+
]
302+
renderWithRouter({ projects: projectsWithEmoji })
303+
304+
// Should extract 'R' from Rocket, not the emoji
305+
const avatar = screen.getByTestId('project-avatar-letter')
306+
expect(avatar).toHaveTextContent('R')
307+
})
308+
309+
it('should preserve emoji-only project names in avatar fallback', () => {
310+
const projectsWithEmojiOnlyName: Project[] = [
311+
{ id: '1', name: '🚀', color: 'blue', gitBranch: 'main' }
312+
]
313+
renderWithRouter({ projects: projectsWithEmojiOnlyName })
314+
315+
// Should keep full emoji grapheme as fallback, not a surrogate fragment
316+
const avatar = screen.getByTestId('project-avatar-letter')
317+
expect(avatar).toHaveTextContent('🚀')
318+
})
245319
})
246320

247321
describe('ProjectSidebar Archived Projects', () => {

0 commit comments

Comments
 (0)