Elysia Tools

Browse tools, examples, visual explainers, and topic guides from one clear workspace.

Top Categories

Hubs

Language
ZHDERUPTENFRES

Elysia Tools

Navigation

Testing

Testing Library Samples

Comprehensive Testing Library examples for React and Vue, covering component testing, user interactions, mocking, and advanced testing patterns

Samples

Entries inside this sample collection

CodetextSimple

React Testing Library Basics

Fundamental React component testing with user-centric queries, assertions, and interaction testing

Difficulty

4/10

Estimated time

20 min

Tags

testing, react, component testing

Prerequisites

React, JavaScript, Jest, DOM basics

text
// React Testing Library Basics
// File: Button.test.js

import { render, screen, fireEvent, waitFor } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import '@testing-library/jest-dom'
import React from 'react'
import Button from '../Button'

// 1. Basic component rendering
describe('Button Component', () => {
  test('renders button with text', () => {
    render(<Button>Click me</Button>)

    // Using user-centric queries
    const button = screen.getByRole('button', { name: /click me/i })
    expect(button).toBeInTheDocument()
    expect(button).toHaveTextContent('Click me')
  })

  // 2. Testing accessibility attributes
  test('applies correct accessibility props', () => {
    render(<Button disabled aria-label="Submit form">Submit</Button>)

    const button = screen.getByRole('button', { name: /submit form/i })
    expect(button).toBeDisabled()
    expect(button).toHaveAttribute('aria-label', 'Submit form')
  })

  // 3. Testing CSS classes and styling
  test('applies custom CSS classes', () => {
    const { container } = render(<Button className="custom-btn primary">Styled Button</Button>)

    const button = screen.getByRole('button', { name: /styled button/i })
    expect(button).toHaveClass('custom-btn', 'primary')
    expect(button).toHaveStyle({ backgroundColor: '#0070f3' })
  })

  // 4. Testing conditional rendering
  test('renders different variants correctly', () => {
    const { rerender } = render(<Button variant="primary">Primary</Button>)

    let button = screen.getByRole('button', { name: /primary/i })
    expect(button).toHaveClass('btn-primary')

    rerender(<Button variant="secondary">Secondary</Button>)
    button = screen.getByRole('button', { name: /secondary/i })
    expect(button).toHaveClass('btn-secondary')
  })

  // 5. Testing click events with fireEvent
  test('handles click events with fireEvent', () => {
    const handleClick = jest.fn()
    render(<Button onClick={handleClick}>Click me</Button>)

    const button = screen.getByRole('button', { name: /click me/i })
    fireEvent.click(button)

    expect(handleClick).toHaveBeenCalledTimes(1)
  })

  // 6. Testing user interactions with userEvent (preferred)
  test('handles user interactions more realistically', async () => {
    const user = userEvent.setup()
    const handleClick = jest.fn()

    render(<Button onClick={handleClick}>Click me</Button>)

    const button = screen.getByRole('button', { name: /click me/i })
    await user.click(button)

    expect(handleClick).toHaveBeenCalledTimes(1)
  })

  // 7. Testing hover and focus states
  test('handles hover and focus states', async () => {
    const user = userEvent.setup()
    render(<Button>Interactive Button</Button>)

    const button = screen.getByRole('button', { name: /interactive button/i })

    // Test hover
    await user.hover(button)
    expect(button).toHaveStyle({ backgroundColor: '#0051cc' })

    // Test focus
    await user.tab()
    expect(button).toHaveFocus()
  })

  // 8. Testing loading state
  test('shows loading state correctly', () => {
    render(<Button loading>Loading Button</Button>)

    const button = screen.getByRole('button', { name: /loading button/i })
    expect(button).toBeDisabled()
    expect(button.querySelector('[data-testid="spinner"]')).toBeInTheDocument()
  })

  // 9. Testing async behavior
  test('handles async actions', async () => {
    const asyncAction = jest.fn(() => Promise.resolve('success'))
    const user = userEvent.setup()

    render(<Button onClick={asyncAction}>Async Button</Button>)

    const button = screen.getByRole('button', { name: /async button/i })
    await user.click(button)

    await waitFor(() => {
      expect(asyncAction).toHaveBeenCalled()
    })
  })

  // 10. Testing custom hooks integration
  test('integrates with custom hooks', () => {
    const TestComponent = () => {
      const [count, setCount] = React.useState(0)
      return (
        <Button onClick={() => setCount(c => c + 1)}>
          Count: {count}
        </Button>
      )
    }

    render(<TestComponent />)

    const button = screen.getByRole('button')
    expect(button).toHaveTextContent('Count: 0')

    fireEvent.click(button)
    expect(button).toHaveTextContent('Count: 1')
  })
})

// File: Form.test.js
import { render, screen, fireEvent, waitFor } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import Form from '../Form'

describe('Form Component', () => {
  test('renders all form fields', () => {
    render(<Form />)

    expect(screen.getByLabelText(/name/i)).toBeInTheDocument()
    expect(screen.getByLabelText(/email/i)).toBeInTheDocument()
    expect(screen.getByLabelText(/password/i)).toBeInTheDocument()
    expect(screen.getByRole('button', { name: /submit/i })).toBeInTheDocument()
  })

  test('validates required fields', async () => {
    const user = userEvent.setup()
    const handleSubmit = jest.fn()

    render(<Form onSubmit={handleSubmit} />)

    const submitButton = screen.getByRole('button', { name: /submit/i })
    await user.click(submitButton)

    // Should show validation errors
    await waitFor(() => {
      expect(screen.getByText(/name is required/i)).toBeInTheDocument()
      expect(screen.getByText(/email is required/i)).toBeInTheDocument()
    })

    // Form should not be submitted
    expect(handleSubmit).not.toHaveBeenCalled()
  })

  test('submits form with valid data', async () => {
    const user = userEvent.setup()
    const handleSubmit = jest.fn()

    render(<Form onSubmit={handleSubmit} />)

    // Fill out form
    await user.type(screen.getByLabelText(/name/i), 'John Doe')
    await user.type(screen.getByLabelText(/email/i), 'john@example.com')
    await user.type(screen.getByLabelText(/password/i), 'password123')

    // Submit form
    await user.click(screen.getByRole('button', { name: /submit/i }))

    await waitFor(() => {
      expect(handleSubmit).toHaveBeenCalledWith({
        name: 'John Doe',
        email: 'john@example.com',
        password: 'password123'
      })
    })
  })

  test('shows submission feedback', async () => {
    const user = userEvent.setup()

    render(<Form />)

    // Fill and submit form
    await user.type(screen.getByLabelText(/name/i), 'John Doe')
    await user.type(screen.getByLabelText(/email/i), 'john@example.com')
    await user.type(screen.getByLabelText(/password/i), 'password123')

    await user.click(screen.getByRole('button', { name: /submit/i }))

    // Should show loading state
    await waitFor(() => {
      expect(screen.getByText(/submitting/i)).toBeInTheDocument()
    })
  })
})

// File: List.test.js
import { render, screen, fireEvent } from '@testing-library/react'
import List from '../List'

describe('List Component', () => {
  const items = [
    { id: 1, name: 'Item 1', completed: false },
    { id: 2, name: 'Item 2', completed: true },
    { id: 3, name: 'Item 3', completed: false }
  ]

  test('renders list items correctly', () => {
    render(<List items={items} />)

    items.forEach(item => {
      expect(screen.getByText(item.name)).toBeInTheDocument()
    })
  })

  test('applies correct styling to completed items', () => {
    render(<List items={items} />)

    const completedItem = screen.getByText('Item 2')
    expect(completedItem).toHaveClass('completed')
  })

  test('filters items correctly', () => {
    const { rerender } = render(<List items={items} filter="completed" />)

    expect(screen.queryByText('Item 1')).not.toBeInTheDocument()
    expect(screen.getByText('Item 2')).toBeInTheDocument()
    expect(screen.queryByText('Item 3')).not.toBeInTheDocument()

    rerender(<List items={items} filter="active" />)

    expect(screen.getByText('Item 1')).toBeInTheDocument()
    expect(screen.queryByText('Item 2')).not.toBeInTheDocument()
    expect(screen.getByText('Item 3')).toBeInTheDocument()
  })

  test('handles item interactions', async () => {
    const onToggleComplete = jest.fn()
    const onDeleteItem = jest.fn()
    const user = userEvent.setup()

    render(
      <List
        items={items}
        onToggleComplete={onToggleComplete}
        onDeleteItem={onDeleteItem}
      />
    )

    // Toggle completion
    const firstItemCheckbox = screen.getAllByRole('checkbox')[0]
    await user.click(firstItemCheckbox)

    expect(onToggleComplete).toHaveBeenCalledWith(1)

    // Delete item
    const deleteButton = screen.getAllByRole('button', { name: /delete/i })[0]
    await user.click(deleteButton)

    expect(onDeleteItem).toHaveBeenCalledWith(1)
  })
})

// File: Modal.test.js
import { render, screen, fireEvent } from '@testing-library/react'
import Modal from '../Modal'

describe('Modal Component', () => {
  test('renders modal when open', () => {
    render(
      <Modal isOpen={true} onClose={jest.fn()}>
        <h1>Modal Content</h1>
        <p>This is a modal</p>
      </Modal>
    )

    expect(screen.getByRole('dialog')).toBeInTheDocument()
    expect(screen.getByText('Modal Content')).toBeInTheDocument()
    expect(screen.getByText('This is a modal')).toBeInTheDocument()
  })

  test('does not render when closed', () => {
    render(
      <Modal isOpen={false} onClose={jest.fn()}>
        <h1>Modal Content</h1>
      </Modal>
    )

    expect(screen.queryByRole('dialog')).not.toBeInTheDocument()
  })

  test('calls onClose when close button is clicked', async () => {
    const onClose = jest.fn()
    const user = userEvent.setup()

    render(
      <Modal isOpen={true} onClose={onClose}>
        <h1>Modal Content</h1>
      </Modal>
    )

    const closeButton = screen.getByRole('button', { name: /close/i })
    await user.click(closeButton)

    expect(onClose).toHaveBeenCalledTimes(1)
  })

  test('calls onClose when overlay is clicked', async () => {
    const onClose = jest.fn()
    const user = userEvent.setup()

    render(
      <Modal isOpen={true} onClose={onClose}>
        <h1>Modal Content</h1>
      </Modal>
    )

    const overlay = screen.getByTestId('modal-overlay')
    await user.click(overlay)

    expect(onClose).toHaveBeenCalledTimes(1)
  })

  test('focuses on first focusable element when opened', () => {
    render(
      <Modal isOpen={true} onClose={jest.fn()}>
        <button>First Button</button>
        <button>Second Button</button>
      </Modal>
    )

    const firstButton = screen.getByRole('button', { name: /first button/i })
    expect(firstButton).toHaveFocus()
  })

  test('traps focus within modal', async () => {
    const user = userEvent.setup()
    render(
      <Modal isOpen={true} onClose={jest.fn()}>
        <button>First Button</button>
        <button>Second Button</button>
        <button>Third Button</button>
      </Modal>
    )

    const buttons = screen.getAllByRole('button')

    // Tab through buttons
    await user.tab()
    expect(buttons[1]).toHaveFocus()

    await user.tab()
    expect(buttons[2]).toHaveFocus()

    // Should cycle back to first element
    await user.tab()
    expect(buttons[0]).toHaveFocus()
  })
})
CodetextComplex

Advanced React Testing Patterns

Complex testing scenarios including API mocking, custom hooks testing, integration testing, and performance testing

Difficulty

8/10

Estimated time

35 min

Tags

testing, react, advanced, integration

Prerequisites

React Testing Library, MSW, Jest, Async/await, Performance concepts

text
// Advanced React Testing Patterns
// File: APITest.test.js

import { render, screen, waitFor, act } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { rest } from 'msw'
import { setupServer } from 'msw/node'
import UserProfile from '../UserProfile'
import '@testing-library/jest-dom'

// Mock API server setup
const server = setupServer(
  rest.get('/api/users/:id', (req, res, ctx) => {
    const { id } = req.params

    if (id === '1') {
      return res(
        ctx.json({
          id: 1,
          name: 'John Doe',
          email: 'john@example.com',
          avatar: 'https://example.com/avatar1.jpg',
          bio: 'Software Developer'
        })
      )
    }

    if (id === '999') {
      return res(
        ctx.status(404),
        ctx.json({ error: 'User not found' })
      )
    }

    return res(ctx.status(500), ctx.json({ error: 'Server error' }))
  }),

  rest.put('/api/users/:id', (req, res, ctx) => {
    return res(
      ctx.json({
        ...req.body,
        updatedAt: new Date().toISOString()
      })
    )
  })
)

// Setup and cleanup
beforeAll(() => server.listen())
afterEach(() => server.resetHandlers())
afterAll(() => server.close())

describe('UserProfile API Integration', () => {
  test('loads and displays user data', async () => {
    render(<UserProfile userId="1" />)

    // Should show loading state initially
    expect(screen.getByText(/loading/i)).toBeInTheDocument()

    // Wait for data to load
    await waitFor(() => {
      expect(screen.getByText('John Doe')).toBeInTheDocument()
      expect(screen.getByText('john@example.com')).toBeInTheDocument()
      expect(screen.getByText('Software Developer')).toBeInTheDocument()
    })

    // Should not show loading state anymore
    expect(screen.queryByText(/loading/i)).not.toBeInTheDocument()
  })

  test('handles user not found error', async () => {
    render(<UserProfile userId="999" />)

    await waitFor(() => {
      expect(screen.getByText(/user not found/i)).toBeInTheDocument()
    })
  })

  test('handles server error gracefully', async () => {
    render(<UserProfile userId="500" />)

    await waitFor(() => {
      expect(screen.getByText(/something went wrong/i)).toBeInTheDocument()
      expect(screen.getByRole('button', { name: /retry/i })).toBeInTheDocument()
    })
  })

  test('allows retrying failed requests', async () => {
    server.use(
      rest.get('/api/users/:id', (req, res, ctx) => {
        return res(ctx.status(500), ctx.json({ error: 'Server error' }))
      })
    )

    render(<UserProfile userId="1" />)

    // Wait for error state
    await waitFor(() => {
      expect(screen.getByText(/something went wrong/i)).toBeInTheDocument()
    })

    // Reset server to respond successfully
    server.resetHandlers()

    // Click retry button
    const retryButton = screen.getByRole('button', { name: /retry/i })
    await userEvent.click(retryButton)

    // Should load successfully now
    await waitFor(() => {
      expect(screen.getByText('John Doe')).toBeInTheDocument()
    })
  })
})

// File: CustomHook.test.js
import { renderHook, act, waitFor } from '@testing-library/react'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import useUser from '../hooks/useUser'
import { rest } from 'msw'
import { setupServer } from 'msw/node'

const server = setupServer(
  rest.get('/api/users/:id', (req, res, ctx) => {
    return res(
      ctx.json({
        id: req.params.id,
        name: 'Test User',
        email: 'test@example.com'
      })
    )
  })
)

beforeAll(() => server.listen())
afterEach(() => server.resetHandlers())
afterAll(() => server.close())

function createWrapper(queryClient) {
  return ({ children }) => (
    <QueryClientProvider client={queryClient}>
      {children}
    </QueryClientProvider>
  )
}

describe('useUser Hook', () => {
  test('loads user data successfully', async () => {
    const queryClient = new QueryClient({
      defaultOptions: {
        queries: { retry: false },
        mutations: { retry: false }
      }
    })

    const { result } = renderHook(() => useUser('1'), {
      wrapper: createWrapper(queryClient)
    })

    expect(result.current.isLoading).toBe(true)
    expect(result.current.user).toBeNull()
    expect(result.current.error).toBeNull()

    await waitFor(() => {
      expect(result.current.isLoading).toBe(false)
      expect(result.current.user).toEqual({
        id: '1',
        name: 'Test User',
        email: 'test@example.com'
      })
      expect(result.current.error).toBeNull()
    })
  })

  test('handles loading state', () => {
    const queryClient = new QueryClient({
      defaultOptions: {
        queries: { retry: false },
        mutations: { retry: false }
      }
    })

    const { result } = renderHook(() => useUser('1'), {
      wrapper: createWrapper(queryClient)
    })

    expect(result.current.isLoading).toBe(true)
    expect(result.current.user).toBeNull()
  })

  test('handles error state', async () => {
    server.use(
      rest.get('/api/users/:id', (req, res, ctx) => {
        return res(ctx.status(404), ctx.json({ error: 'Not found' }))
      })
    )

    const queryClient = new QueryClient({
      defaultOptions: {
        queries: { retry: false },
        mutations: { retry: false }
      }
    })

    const { result } = renderHook(() => useUser('999'), {
      wrapper: createWrapper(queryClient)
    })

    await waitFor(() => {
      expect(result.current.isLoading).toBe(false)
      expect(result.current.user).toBeNull()
      expect(result.current.error).toBeTruthy()
    })
  })

  test('refetches data', async () => {
    const queryClient = new QueryClient({
      defaultOptions: {
        queries: { retry: false },
        mutations: { retry: false }
      }
    })

    const { result } = renderHook(() => useUser('1'), {
      wrapper: createWrapper(queryClient)
    })

    // Wait for initial load
    await waitFor(() => {
      expect(result.current.user).toBeTruthy()
    })

    const initialUser = result.current.user

    // Mock different data for refetch
    server.use(
      rest.get('/api/users/:id', (req, res, ctx) => {
        return res(
          ctx.json({
            id: req.params.id,
            name: 'Updated User',
            email: 'updated@example.com'
          })
        )
      })
    )

    // Refetch data
    await act(async () => {
      await result.current.refetch()
    })

    await waitFor(() => {
      expect(result.current.user).toEqual({
        id: '1',
        name: 'Updated User',
        email: 'updated@example.com'
      })
    })

    expect(result.current.user).not.toEqual(initialUser)
  })
})

// File: Integration.test.js
import { render, screen, fireEvent, waitFor } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { rest } from 'msw'
import { setupServer } from 'msw/node'
import App from '../App'
import '@testing-library/jest-dom'

const server = setupServer(
  rest.get('/api/posts', (req, res, ctx) => {
    return res(
      ctx.json([
        { id: 1, title: 'First Post', content: 'First content' },
        { id: 2, title: 'Second Post', content: 'Second content' }
      ])
    )
  }),

  rest.post('/api/posts', (req, res, ctx) => {
    return res(
      ctx.json({
        id: 3,
        ...req.body,
        createdAt: new Date().toISOString()
      })
    )
  })
)

beforeAll(() => server.listen())
afterEach(() => server.resetHandlers())
afterAll(() => server.close())

describe('App Integration Tests', () => {
  test('renders full application flow', async () => {
    render(<App />)

    // Should show initial loading
    expect(screen.getByText(/loading posts/i)).toBeInTheDocument()

    // Should render posts after loading
    await waitFor(() => {
      expect(screen.getByText('First Post')).toBeInTheDocument()
      expect(screen.getByText('Second Post')).toBeInTheDocument()
    })
  })

  test('creates new post successfully', async () => {
    const user = userEvent.setup()
    render(<App />)

    // Wait for posts to load
    await waitFor(() => {
      expect(screen.getByText('First Post')).toBeInTheDocument()
    })

    // Open new post form
    const newPostButton = screen.getByRole('button', { name: /new post/i })
    await user.click(newPostButton)

    // Fill out form
    await user.type(screen.getByLabelText(/title/i), 'New Test Post')
    await user.type(screen.getByLabelText(/content/i), 'New test content')

    // Submit form
    await user.click(screen.getByRole('button', { name: /create post/i }))

    // Should show new post in list
    await waitFor(() => {
      expect(screen.getByText('New Test Post')).toBeInTheDocument()
      expect(screen.getByText('New test content')).toBeInTheDocument()
    })
  })

  test('handles API errors gracefully', async () => {
    server.use(
      rest.get('/api/posts', (req, res, ctx) => {
        return res(ctx.status(500), ctx.json({ error: 'Server error' }))
      })
    )

    render(<App />)

    await waitFor(() => {
      expect(screen.getByText(/failed to load posts/i)).toBeInTheDocument()
      expect(screen.getByRole('button', { name: /retry/i })).toBeInTheDocument()
    })
  })

  test('maintains state during navigation', async () => {
    const user = userEvent.setup()
    render(<App />)

    // Wait for initial load
    await waitFor(() => {
      expect(screen.getByText('First Post')).toBeInTheDocument()
    })

    // Navigate to a post
    const firstPostLink = screen.getByRole('link', { name: /first post/i })
    await user.click(firstPostLink)

    // Should show post details
    await waitFor(() => {
      expect(screen.getByText('First content')).toBeInTheDocument()
    })

    // Navigate back
    const backButton = screen.getByRole('button', { name: /back/i })
    await user.click(backButton)

    // Should show post list again
    await waitFor(() => {
      expect(screen.getByText('First Post')).toBeInTheDocument()
      expect(screen.getByText('Second Post')).toBeInTheDocument()
    })
  })
})

// File: Performance.test.js
import { render, screen } from '@testing-library/react'
import { measure } from 'v8-performance'
import LargeList from '../LargeList'

describe('Performance Tests', () => {
  // Generate large dataset for performance testing
  const generateLargeDataset = (size) => {
    return Array.from({ length: size }, (_, index) => ({
      id: index + 1,
      name: `Item ${index + 1}`,
      description: `Description for item ${index + 1}`,
      category: `Category ${(index % 10) + 1}`
    }))
  }

  test('renders large list efficiently', () => {
    const largeData = generateLargeDataset(1000)

    // Measure render time
    const startTime = performance.now()

    render(<LargeList items={largeData} />)

    const endTime = performance.now()
    const renderTime = endTime - startTime

    // Render should complete within reasonable time
    expect(renderTime).toBeLessThan(1000) // 1 second

    // Should render initial items
    expect(screen.getAllByRole('listitem').length).toBeGreaterThan(0)
  })

  test('handles filtering efficiently', () => {
    const largeData = generateLargeDataset(1000)
    const { rerender } = render(<LargeList items={largeData} />)

    const initialItems = screen.getAllByRole('listitem')
    expect(initialItems.length).toBeLessThan(1000) // Due to virtualization

    // Filter to specific category
    rerender(<LargeList items={largeData} filter="Category 1" />)

    const filteredItems = screen.getAllByRole('listitem')

    // Should update filter quickly
    const filterStartTime = performance.now()

    // Trigger filter logic (this would be handled by the component)
    fireEvent.change(screen.getByRole('textbox', { name: /filter/i }), {
      target: { value: 'Category 1' }
    })

    const filterEndTime = performance.now()
    const filterTime = filterEndTime - filterStartTime

    expect(filterTime).toBeLessThan(100) // Filter should be very fast
  })

  test('memory usage remains reasonable', () => {
    const largeData = generateLargeDataset(5000)

    const initialMemory = performance.memory?.usedJSHeapSize || 0

    const { unmount } = render(<LargeList items={largeData} />)

    const afterRenderMemory = performance.memory?.usedJSHeapSize || 0
    const memoryIncrease = afterRenderMemory - initialMemory

    // Memory increase should be reasonable (less than 50MB)
    expect(memoryIncrease).toBeLessThan(50 * 1024 * 1024)

    // Cleanup and check memory release
    unmount()

    // Force garbage collection if available
    if (global.gc) {
      global.gc()
    }
  })

  test('handles frequent updates efficiently', async () => {
    const initialData = generateLargeDataset(100)

    render(<LargeList items={initialData} />)

    const startTime = performance.now()

    // Simulate frequent updates
    for (let i = 0; i < 10; i++) {
      const newData = generateLargeDataset(100 + i * 10)

      // This would be handled by parent component updating props
      // For testing, we simulate the update time
      const updateStart = performance.now()

      // Trigger re-render (in real scenario, this would be props update)
      fireEvent.click(screen.getByRole('button', { name: /refresh/i }))

      const updateEnd = performance.now()
      const updateTime = updateEnd - updateStart

      // Each update should be fast
      expect(updateTime).toBeLessThan(100)
    }

    const totalTime = performance.now() - startTime

    // Total time for all updates should be reasonable
    expect(totalTime).toBeLessThan(2000) // 2 seconds
  })
})
CodetextSimple

Vue Testing Library Basics

Essential Vue component testing with Vue Testing Library, covering Vue 3 Composition API, component interactions, and testing utilities

Difficulty

4/10

Estimated time

20 min

Tags

testing, vue, component testing

Prerequisites

Vue 3, JavaScript, Testing basics, Composition API

text
// Vue Testing Library Basics
// File: Button.spec.js

import { mount } from '@vue/test-utils'
import { describe, it, expect, vi } from 'vitest'
import Button from '../Button.vue'

describe('Button Component', () => {
  it('renders button with text', () => {
    const wrapper = mount(Button, {
      props: {
        text: 'Click me'
      }
    })

    expect(wrapper.text()).toContain('Click me')
    expect(wrapper.find('button').exists()).toBe(true)
  })

  it('applies correct CSS classes', () => {
    const wrapper = mount(Button, {
      props: {
        variant: 'primary',
        size: 'large'
      }
    })

    const button = wrapper.find('button')
    expect(button.classes()).toContain('btn-primary')
    expect(button.classes()).toContain('btn-large')
  })

  it('emits click event', async () => {
    const wrapper = mount(Button, {
      props: {
        text: 'Click me'
      }
    })

    await wrapper.find('button').trigger('click')

    expect(wrapper.emitted()).toHaveProperty('click')
    expect(wrapper.emitted('click')).toHaveLength(1)
  })

  it('is disabled when disabled prop is true', () => {
    const wrapper = mount(Button, {
      props: {
        text: 'Disabled Button',
        disabled: true
      }
    })

    const button = wrapper.find('button')
    expect(button.attributes('disabled')).toBeDefined()
    expect(button.element.disabled).toBe(true)
  })

  it('shows loading state', () => {
    const wrapper = mount(Button, {
      props: {
        text: 'Loading',
        loading: true
      }
    })

    const button = wrapper.find('button')
    expect(button.find('[data-testid="spinner"]').exists()).toBe(true)
    expect(button.attributes('disabled')).toBeDefined()
  })

  it('renders slot content when provided', () => {
    const wrapper = mount(Button, {
      slots: {
        default: '<span class="custom-content">Custom Content</span>'
      }
    })

    expect(wrapper.find('.custom-content').exists()).toBe(true)
    expect(wrapper.text()).toContain('Custom Content')
  })

  it('handles keyboard events', async () => {
    const wrapper = mount(Button, {
      props: {
        text: 'Keyboard Button'
      }
    })

    await wrapper.find('button').trigger('keydown.enter')

    expect(wrapper.emitted()).toHaveProperty('click')
  })
})

// File: TodoList.spec.js

import { mount } from '@vue/test-utils'
import { describe, it, expect, beforeEach } from 'vitest'
import { nextTick } from 'vue'
import TodoList from '../TodoList.vue'

describe('TodoList Component', () => {
  let wrapper

  beforeEach(() => {
    wrapper = mount(TodoList, {
      props: {
        todos: [
          { id: 1, text: 'Learn Vue', completed: false },
          { id: 2, text: 'Build App', completed: true },
          { id: 3, text: 'Deploy App', completed: false }
        ]
      }
    })
  })

  it('renders all todos', () => {
    const todoItems = wrapper.findAll('[data-testid="todo-item"]')
    expect(todoItems).toHaveLength(3)
    expect(wrapper.text()).toContain('Learn Vue')
    expect(wrapper.text()).toContain('Build App')
    expect(wrapper.text()).toContain('Deploy App')
  })

  it('marks todo as completed', async () => {
    const firstTodo = wrapper.find('[data-testid="todo-item"]')
    const checkbox = firstTodo.find('input[type="checkbox"]')

    await checkbox.setChecked(true)
    await nextTick()

    expect(firstTodo.classes()).toContain('completed')
    expect(wrapper.emitted()).toHaveProperty('toggle-completed')
  })

  it('filters todos correctly', async () => {
    // Test active filter
    await wrapper.setData({ filter: 'active' })
    await nextTick()

    const activeTodos = wrapper.findAll('[data-testid="todo-item"]:not(.completed)')
    expect(activeTodos).toHaveLength(2)

    // Test completed filter
    await wrapper.setData({ filter: 'completed' })
    await nextTick()

    const completedTodos = wrapper.findAll('[data-testid="todo-item"].completed')
    expect(completedTodos).toHaveLength(1)
  })

  it('adds new todo', async () => {
    const newTodoInput = wrapper.find('[data-testid="new-todo-input"]')
    const addButton = wrapper.find('[data-testid="add-todo-button"]')

    await newTodoInput.setValue('New Todo Item')
    await addButton.trigger('click')
    await nextTick()

    expect(wrapper.emitted()).toHaveProperty('add-todo')
    expect(wrapper.emitted('add-todo')[0]).toEqual([{ text: 'New Todo Item' }])
  })

  it('deletes todo', async () => {
    const firstTodo = wrapper.find('[data-testid="todo-item"]')
    const deleteButton = firstTodo.find('[data-testid="delete-button"]')

    await deleteButton.trigger('click')
    await nextTick()

    expect(wrapper.emitted()).toHaveProperty('delete-todo')
    expect(wrapper.emitted('delete-todo')[0]).toEqual([1])
  })
})

// File: Form.spec.js

import { mount } from '@vue/test-utils'
import { describe, it, expect, vi } from 'vitest'
import { nextTick } from 'vue'
import ContactForm from '../ContactForm.vue'

describe('ContactForm Component', () => {
  it('renders form fields correctly', () => {
    const wrapper = mount(ContactForm)

    expect(wrapper.find('[name="name"]').exists()).toBe(true)
    expect(wrapper.find('[name="email"]').exists()).toBe(true)
    expect(wrapper.find('[name="message"]').exists()).toBe(true)
    expect(wrapper.find('button[type="submit"]').exists()).toBe(true)
  })

  it('validates required fields', async () => {
    const wrapper = mount(ContactForm)
    const submitButton = wrapper.find('button[type="submit"]')

    await submitButton.trigger('click')
    await nextTick()

    expect(wrapper.text()).toContain('Name is required')
    expect(wrapper.text()).toContain('Email is required')
    expect(wrapper.text()).toContain('Message is required')
  })

  it('validates email format', async () => {
    const wrapper = mount(ContactForm)

    await wrapper.find('[name="email"]').setValue('invalid-email')
    await wrapper.find('button[type="submit"]').trigger('click')
    await nextTick()

    expect(wrapper.text()).toContain('Please enter a valid email')
  })

  it('submits form with valid data', async () => {
    const wrapper = mount(ContactForm)

    await wrapper.find('[name="name"]').setValue('John Doe')
    await wrapper.find('[name="email"]').setValue('john@example.com')
    await wrapper.find('[name="message"]').setValue('This is a test message')
    await wrapper.find('button[type="submit"]').trigger('click')
    await nextTick()

    expect(wrapper.emitted()).toHaveProperty('submit')
    expect(wrapper.emitted('submit')[0]).toEqual({
      name: 'John Doe',
      email: 'john@example.com',
      message: 'This is a test message'
    })
  })

  it('shows loading state during submission', async () => {
    const wrapper = mount(ContactForm)

    // Mock async submission
    const submitSpy = vi.fn(() => Promise.resolve())
    wrapper.vm.submit = submitSpy

    await wrapper.find('[name="name"]').setValue('John Doe')
    await wrapper.find('[name="email"]').setValue('john@example.com')
    await wrapper.find('[name="message"]').setValue('Test message')
    await wrapper.find('button[type="submit"]').trigger('click')

    expect(wrapper.find('button[type="submit"]').attributes('disabled')).toBeDefined()
    expect(wrapper.text()).toContain('Submitting...')
  })
})

// File: Counter.spec.js

import { mount } from '@vue/test-utils'
import { describe, it, expect, beforeEach } from 'vitest'
import Counter from '../Counter.vue'

describe('Counter Component', () => {
  let wrapper

  beforeEach(() => {
    wrapper = mount(Counter, {
      props: {
        initialValue: 5
      }
    })
  })

  it('renders initial value', () => {
    expect(wrapper.text()).toContain('Count: 5')
  })

  it('increments count when increment button is clicked', async () => {
    const incrementButton = wrapper.find('[data-testid="increment"]')

    await incrementButton.trigger('click')
    await wrapper.vm.$nextTick()

    expect(wrapper.text()).toContain('Count: 6')
  })

  it('decrements count when decrement button is clicked', async () => {
    const decrementButton = wrapper.find('[data-testid="decrement"]')

    await decrementButton.trigger('click')
    await wrapper.vm.$nextTick()

    expect(wrapper.text()).toContain('Count: 4')
  })

  it('resets count when reset button is clicked', async () => {
    const incrementButton = wrapper.find('[data-testid="increment"]')
    const resetButton = wrapper.find('[data-testid="reset"]')

    await incrementButton.trigger('click')
    await incrementButton.trigger('click')
    await wrapper.vm.$nextTick()

    expect(wrapper.text()).toContain('Count: 7')

    await resetButton.trigger('click')
    await wrapper.vm.$nextTick()

    expect(wrapper.text()).toContain('Count: 5')
  })

  it('does not go below minimum value', async () => {
    wrapper = mount(Counter, {
      props: {
        initialValue: 0,
        min: 0
      }
    })

    const decrementButton = wrapper.find('[data-testid="decrement"]')

    await decrementButton.trigger('click')
    await wrapper.vm.$nextTick()

    expect(wrapper.text()).toContain('Count: 0')
    expect(wrapper.find('[data-testid="decrement"]').attributes('disabled')).toBeDefined()
  })

  it('does not go above maximum value', async () => {
    wrapper = mount(Counter, {
      props: {
        initialValue: 10,
        max: 10
      }
    })

    const incrementButton = wrapper.find('[data-testid="increment"]')

    await incrementButton.trigger('click')
    await wrapper.vm.$nextTick()

    expect(wrapper.text()).toContain('Count: 10')
    expect(wrapper.find('[data-testid="increment"]').attributes('disabled')).toBeDefined()
  })

  it('emits change event when count changes', async () => {
    const incrementButton = wrapper.find('[data-testid="increment"]')

    await incrementButton.trigger('click')
    await wrapper.vm.$nextTick()

    expect(wrapper.emitted()).toHaveProperty('change')
    expect(wrapper.emitted('change')[0]).toEqual(6)
  })
})

// File: Modal.spec.js

import { mount } from '@vue/test-utils'
import { describe, it, expect } from 'vitest'
import Modal from '../Modal.vue'

describe('Modal Component', () => {
  it('renders when open prop is true', () => {
    const wrapper = mount(Modal, {
      props: {
        open: true,
        title: 'Test Modal'
      },
      slots: {
        default: '<p>Modal content</p>'
      }
    })

    expect(wrapper.find('[data-testid="modal"]').exists()).toBe(true)
    expect(wrapper.text()).toContain('Test Modal')
    expect(wrapper.text()).toContain('Modal content')
  })

  it('does not render when open prop is false', () => {
    const wrapper = mount(Modal, {
      props: {
        open: false
      }
    })

    expect(wrapper.find('[data-testid="modal"]').exists()).toBe(false)
  })

  it('emits close event when close button is clicked', async () => {
    const wrapper = mount(Modal, {
      props: {
        open: true
      }
    })

    const closeButton = wrapper.find('[data-testid="close-button"]')
    await closeButton.trigger('click')

    expect(wrapper.emitted()).toHaveProperty('close')
  })

  it('emits close event when overlay is clicked', async () => {
    const wrapper = mount(Modal, {
      props: {
        open: true
      }
    })

    const overlay = wrapper.find('[data-testid="modal-overlay"]')
    await overlay.trigger('click')

    expect(wrapper.emitted()).toHaveProperty('close')
  })

  it('prevents closing when preventClose is true', async () => {
    const wrapper = mount(Modal, {
      props: {
        open: true,
        preventClose: true
      }
    })

    const overlay = wrapper.find('[data-testid="modal-overlay"]')
    await overlay.trigger('click')

    expect(wrapper.emitted('close')).toBeUndefined()
  })

  it('applies custom size class', () => {
    const wrapper = mount(Modal, {
      props: {
        open: true,
        size: 'large'
      }
    })

    const modal = wrapper.find('[data-testid="modal"]')
    expect(modal.classes()).toContain('modal-large')
  })
})
CodetextComplex

Advanced Vue Testing Patterns

Complex Vue testing scenarios including Pinia store testing, router testing, API integration, and component communication patterns

Difficulty

8/10

Estimated time

35 min

Tags

testing, vue, advanced, integration

Prerequisites

Vue Testing Library, Pinia, Vue Router, Async/await, Component communication

text
// Advanced Vue Testing Patterns
// File: StoreIntegration.spec.js

import { mount } from '@vue/test-utils'
import { describe, it, expect, beforeEach, vi } from 'vitest'
import { createPinia, setActivePinia } from 'pinia'
import { nextTick } from 'vue'
import UserProfile from '../UserProfile.vue'
import { useUserStore } from '../stores/userStore'

describe('Store Integration Tests', () => {
  let wrapper
  let pinia

  beforeEach(() => {
    pinia = createPinia()
    setActivePinia(pinia)
  })

  it('loads and displays user data from store', async () => {
    // Mock store data
    const userStore = useUserStore()
    userStore.user = {
      id: 1,
      name: 'John Doe',
      email: 'john@example.com',
      avatar: 'avatar.jpg'
    }
    userStore.loading = false

    wrapper = mount(UserProfile, {
      global: {
        plugins: [pinia]
      }
    })

    expect(wrapper.text()).toContain('John Doe')
    expect(wrapper.text()).toContain('john@example.com')
  })

  it('shows loading state when store is loading', () => {
    const userStore = useUserStore()
    userStore.loading = true
    userStore.user = null

    wrapper = mount(UserProfile, {
      global: {
        plugins: [pinia]
      }
    })

    expect(wrapper.text()).toContain('Loading...')
  })

  it('dispatches store actions on user actions', async () => {
    const userStore = useUserStore()
    userStore.user = {
      id: 1,
      name: 'John Doe',
      email: 'john@example.com'
    }
    userStore.loading = false

    // Mock store action
    const updateProfileSpy = vi.spyOn(userStore, 'updateProfile')

    wrapper = mount(UserProfile, {
      global: {
        plugins: [pinia]
      }
    })

    // Find and trigger edit mode
    const editButton = wrapper.find('[data-testid="edit-profile"]')
    await editButton.trigger('click')

    await nextTick()

    // Update form fields
    const nameInput = wrapper.find('[data-testid="name-input"]')
    await nameInput.setValue('Jane Doe')

    const saveButton = wrapper.find('[data-testid="save-profile"]')
    await saveButton.trigger('click')

    await nextTick()

    expect(updateProfileSpy).toHaveBeenCalledWith({
      name: 'Jane Doe'
    })
  })

  it('handles store errors correctly', async () => {
    const userStore = useUserStore()
    userStore.loading = false
    userStore.error = 'Failed to load user'

    wrapper = mount(UserProfile, {
      global: {
        plugins: [pinia]
      }
    })

    expect(wrapper.text()).toContain('Failed to load user')
    expect(wrapper.find('[data-testid="error-message"]').exists()).toBe(true)
  })
})

// File: RouterIntegration.spec.js

import { mount } from '@vue/test-utils'
import { describe, it, expect, vi } from 'vitest'
import { createRouter, createWebHistory } from 'vue-router'
import { nextTick } from 'vue'
import App from '../App.vue'

// Mock components
const Home = { template: '<div>Home Page</div>' }
const About = { template: '<div>About Page</div>' }
const UserProfile = { template: '<div>User Profile: {{ $route.params.id }}</div>' }

describe('Router Integration Tests', () => {
  let router
  let wrapper

  beforeEach(async () => {
    router = createRouter({
      history: createWebHistory(),
      routes: [
        { path: '/', component: Home },
        { path: '/about', component: About },
        { path: '/user/:id', component: UserProfile, name: 'user-profile' }
      ]
    })

    wrapper = mount(App, {
      global: {
        plugins: [router]
      }
    })

    await router.isReady()
  })

  it('renders home page by default', () => {
    expect(wrapper.text()).toContain('Home Page')
  })

  it('navigates to about page', async () => {
    const aboutLink = wrapper.find('[data-testid="about-link"]')
    await aboutLink.trigger('click')

    await nextTick()
    await new Promise(resolve => setTimeout(resolve, 0))

    expect(wrapper.text()).toContain('About Page')
  })

  it('navigates to user profile with dynamic route', async () => {
    await router.push('/user/123')
    await nextTick()

    expect(wrapper.text()).toContain('User Profile: 123')
  })

  it('updates route params correctly', async () => {
    await router.push('/user/123')
    await nextTick()
    expect(wrapper.text()).toContain('User Profile: 123')

    await router.push('/user/456')
    await nextTick()
    expect(wrapper.text()).toContain('User Profile: 456')
  })

  it('handles navigation guards', async () => {
    // Add navigation guard
    router.beforeEach((to, from, next) => {
      if (to.path === '/about') {
        next('/login')
      } else {
        next()
      }
    })

    const aboutLink = wrapper.find('[data-testid="about-link"]')
    await aboutLink.trigger('click')

    await nextTick()
    await new Promise(resolve => setTimeout(resolve, 0))

    expect(wrapper.vm.$route.path).toBe('/login')
  })

  it('passes route params as props', async () => {
    const TestComponent = {
      template: '<div>User ID: {{ userId }}</div>',
      props: ['userId']
    }

    router.addRoute({
      path: '/profile/:userId',
      component: TestComponent,
      props: true
    })

    await router.push('/profile/789')
    await nextTick()

    expect(wrapper.text()).toContain('User ID: 789')
  })
})

// File: ComponentCommunication.spec.js

import { mount } from '@vue/test-utils'
import { describe, it, expect, vi } from 'vitest'
import { nextTick } from 'vue'
import ParentComponent from '../ParentComponent.vue'
import ChildComponent from '../ChildComponent.vue'

describe('Component Communication Tests', () => {
  it('passes data from parent to child via props', () => {
    const wrapper = mount(ParentComponent, {
      props: {
        message: 'Hello from parent'
      }
    })

    const childComponent = wrapper.findComponent(ChildComponent)
    expect(childComponent.props('message')).toBe('Hello from parent')
    expect(wrapper.text()).toContain('Child says: Hello from parent')
  })

  it('emits events from child to parent', async () => {
    const wrapper = mount(ParentComponent)
    const childComponent = wrapper.findComponent(ChildComponent)

    await childComponent.vm.$emit('child-event', 'Hello from child')

    expect(wrapper.emitted('child-event')).toBeTruthy()
    expect(wrapper.emitted('child-event')[0]).toEqual(['Hello from child'])
  })

  it('updates parent state based on child events', async () => {
    const wrapper = mount(ParentComponent)
    const childComponent = wrapper.findComponent(ChildComponent)

    // Child component emits an update event
    await childComponent.vm.$emit('update-message', 'Updated message')

    await nextTick()

    // Parent should reflect the updated message
    expect(wrapper.vm.message).toBe('Updated message')
    expect(wrapper.text()).toContain('Child says: Updated message')
  })

  it('communicates via provide/inject', () => {
    const ParentComponent = {
      template: `
        <div>
          <ChildComponent />
        </div>
      `,
      provide: {
        sharedData: 'Shared from parent',
        sharedMethod: vi.fn()
      }
    }

    const ChildComponent = {
      template: `
        <div>{{ injectedData }}</div>
      `,
      inject: ['sharedData', 'sharedMethod']
    }

    const wrapper = mount(ParentComponent, {
      global: {
        components: { ChildComponent }
      }
    })

    const childComponent = wrapper.findComponent(ChildComponent)
    expect(childComponent.vm.sharedData).toBe('Shared from parent')
    expect(childComponent.vm.sharedMethod).toBeDefined()
  })

  it('communicates via event bus', async () => {
    const eventBus = mitt()

    const EmitterComponent = {
      template: '<button @click="emitEvent">Emit Event</button>',
      methods: {
        emitEvent() {
          eventBus.emit('test-event', 'Hello from emitter')
        }
      }
    }

    const ListenerComponent = {
      template: '<div>{{ receivedMessage }}</div>',
      data() {
        return {
          receivedMessage: ''
        }
      },
      mounted() {
        eventBus.on('test-event', (message) => {
          this.receivedMessage = message
        })
      }
    }

    const wrapper = mount({
      template: `
        <div>
          <EmitterComponent ref="emitter" />
          <ListenerComponent ref="listener" />
        </div>
      `,
      components: {
        EmitterComponent,
        ListenerComponent
      }
    })

    const emitter = wrapper.findComponent({ name: 'EmitterComponent' })
    await emitter.find('button').trigger('click')

    await nextTick()

    const listener = wrapper.findComponent({ name: 'ListenerComponent' })
    expect(listener.vm.receivedMessage).toBe('Hello from emitter')
  })
})

// File: AsyncComponent.spec.js

import { mount } from '@vue/test-utils'
import { describe, it, expect, vi, beforeEach } from 'vitest'
import { nextTick } from 'vue'
import AsyncDataLoader from '../AsyncDataLoader.vue'

describe('Async Component Tests', () => {
  let wrapper

  beforeEach(() => {
    vi.clearAllMocks()
  })

  it('shows loading state initially', () => {
    wrapper = mount(AsyncDataLoader)
    expect(wrapper.text()).toContain('Loading...')
  })

  it('loads and displays data on mount', async () => {
    // Mock API call
    const mockFetch = vi.fn(() =>
      Promise.resolve({
        json: () => Promise.resolve({ data: ['item1', 'item2', 'item3'] })
      })
    )
    global.fetch = mockFetch

    wrapper = mount(AsyncDataLoader)

    // Wait for async operation
    await nextTick()
    await new Promise(resolve => setTimeout(resolve, 100))

    expect(mockFetch).toHaveBeenCalledTimes(1)
    expect(wrapper.text()).toContain('item1')
    expect(wrapper.text()).toContain('item2')
    expect(wrapper.text()).toContain('item3')
  })

  it('handles API errors gracefully', async () => {
    // Mock failed API call
    const mockFetch = vi.fn(() =>
      Promise.reject(new Error('Network error'))
    )
    global.fetch = mockFetch

    wrapper = mount(AsyncDataLoader)

    await nextTick()
    await new Promise(resolve => setTimeout(resolve, 100))

    expect(wrapper.text()).toContain('Failed to load data')
  })

  it('can refresh data', async () => {
    let callCount = 0
    const mockFetch = vi.fn(() => {
      callCount++
      return Promise.resolve({
        json: () => Promise.resolve({ data: [`item${callCount}`] })
      })
    })
    global.fetch = mockFetch

    wrapper = mount(AsyncDataLoader)

    // Initial load
    await nextTick()
    await new Promise(resolve => setTimeout(resolve, 100))
    expect(wrapper.text()).toContain('item1')

    // Trigger refresh
    const refreshButton = wrapper.find('[data-testid="refresh-button"]')
    await refreshButton.trigger('click')

    await nextTick()
    await new Promise(resolve => setTimeout(resolve, 100))

    expect(callCount).toBe(2)
    expect(wrapper.text()).toContain('item2')
  })

  it('debounces rapid requests', async () => {
    const mockFetch = vi.fn(() =>
      Promise.resolve({
        json: () => Promise.resolve({ data: ['debounced-item'] })
      })
    )
    global.fetch = mockFetch

    wrapper = mount(AsyncDataLoader)

    const searchInput = wrapper.find('[data-testid="search-input"]')

    // Trigger multiple rapid changes
    await searchInput.setValue('search1')
    await searchInput.setValue('search2')
    await searchInput.setValue('search3')

    // Wait for debounce timeout
    await new Promise(resolve => setTimeout(resolve, 300))

    // Should only call API once due to debouncing
    expect(mockFetch).toHaveBeenCalledTimes(1)
  })
})

Tools

Tools frequently paired with this sample

Related

Related sample collections

Related

Related workflows

Hub

Infer JSON Schema from Samples and Spreadsheets

Derive a reviewable JSON Schema draft from representative JSON samples or XLSX rows, then inspect types, requiredness, nulls, and outliers before treating it as a contract.

Hub

Batch Audio Library Cleanup and Delivery

Take a pile of mixed audio files to one shippable library — find and judge duplicates, convert the whole batch to a single format with deliberate encoder settings, fix the CBR or VBR bitrate policy, repair tags and filenames in bulk, and correct playback speed without touching pitch.

Hub

Deliberate Text Corruption and Mutation for Testing

Break clean text on purpose — filter, duplicate, and reverse sentences and words, inject random letters and symbols, shuffle lines and words, and prove every mutation stays controlled for parser stress tests, OCR rehearsal, and language experiments.

Hub

cURL API Request Conversion and Testing

Convert a cURL request into code or HAR, test it safely, and explain the HTTP status without losing headers, body, or auth context.

Home
Tools3212
Workbench
Samples593
Visualizations471
Viewers103
Hubs239
Tags333
Images, Audio & Video657

Image, audio, and video processing, conversion, and optimization tools

Math, Date & Finance647

Calculators, numerics, date logic, statistics, and finance tools

Design & Color298

Color, layout, graphics, visual styling, and design helper tools

Text & Writing209

Writing, cleanup, formatting, extraction, and text analysis tools

Developer & Web193

Developer utilities, networking, web debugging, and automation helpers

Conversion & Encoding175

Format, file, archive, unit, and encoding conversion tools

Lead Generation Quiz Launch and Contact Handoff
Memorial Drafts: Family Review and Print Handoff
Private Habit Records: Backup, Restore and Sharing Review
Article to X and LinkedIn Drafts: Fact Review and Handoff
Markdown Interactive Deck Review and Offline Handoff

© 2026 Elysia Tools. All rights reserved.

DocsPricingAboutTerms of ServicePrivacy PolicyCookiesContact

Media

Duplicate Audio Library Finder

Find exact and near-duplicate audio across uploaded files or a ZIP, including copies saved with different codecs.

Development

AI Regex Explainer

Use AI to break down regular expressions into readable explanations

Media

Batch Audio Rename

Batch rename audio files using patterns, text replacement, numbering, and case conversion. Returns renamed files as a ZIP download.

Development

Glob to Regex

Convert file matching patterns (Glob) to regular expressions

Text Processing

Hashtag & Mention Extractor

Extract hashtags (#Topic) and user mentions (@Username) from social media text like Twitter, Instagram, etc.

Design

Add Texture Effect

Add various texture overlays to images with customizable blend modes and intensity

Media

Batch Image Rename

Batch rename image files using patterns, text replacement, numbering, and case conversion. Returns renamed files as a ZIP download.

Development

Multi-Pattern Matcher

Match multiple regex patterns against text in one operation

Testing

Jest Testing Framework

Comprehensive Jest testing examples including unit tests, integration tests, mocking, async testing, and advanced patterns for JavaScript/TypeScript applications

Testing

BDD with Cucumber - Behavior Driven Development

Comprehensive Cucumber BDD examples including feature files, step definitions, data tables, hooks, and advanced BDD patterns for collaborative development

Testing

GitHub Actions Testing - CI/CD Integration

Comprehensive GitHub Actions testing workflows including automated testing, parallel execution, test reporting, caching, and advanced CI/CD patterns for modern development pipelines

Testing

K6 Modern Performance Testing Tool

Comprehensive K6 performance testing examples including load testing, stress testing, API performance testing, and advanced patterns for modern applications

Testing

Playwright E2E Testing Framework

Comprehensive Playwright testing examples including cross-browser automation, API testing, mobile testing, visual regression, and advanced E2E patterns for modern web applications

Testing

Test Pyramid Examples - Testing Strategy Guide

Comprehensive test pyramid implementation examples including unit tests, integration tests, E2E tests, test organization, and strategic testing patterns for balanced software quality assurance