{"id":14038,"library":"souvlaki","title":"Souvlaki: Composable React Test Wrappers","description":"Souvlaki is a TypeScript-first library designed to simplify testing React components that rely heavily on context or multiple providers. It offers composable utilities to create and combine test wrappers, abstracting away the boilerplate often associated with setting up complex testing environments for components using Redux, React Router, Apollo, or custom contexts. The package is currently at version 0.3.1. While the author notes it's 'more or less finished' and doesn't receive regular updates, it is actively used and considered maintained, implying a stable but slow release cadence. Its key differentiator is simplifying the management of multiple providers in tests, offering a cleaner alternative to manually creating custom `render` functions or nesting providers directly in every test, thereby promoting more maintainable and readable test suites when used with React Testing Library.","status":"maintenance","version":"0.3.1","language":"javascript","source_language":"en","source_url":"git@github.com:camjackson/souvlaki","tags":["javascript","typescript"],"install":[{"cmd":"npm install souvlaki","lang":"bash","label":"npm"},{"cmd":"yarn add souvlaki","lang":"bash","label":"yarn"},{"cmd":"pnpm add souvlaki","lang":"bash","label":"pnpm"}],"dependencies":[{"reason":"Peer dependency for building React components.","package":"react","optional":false},{"reason":"Peer dependency for rendering React components in a DOM environment, typically for testing.","package":"react-dom","optional":false}],"imports":[{"note":"Main utility for composing simple wrappers. Souvlaki ships TypeScript types and is primarily used with ESM imports.","wrong":"const { createWrapper } = require('souvlaki');","symbol":"createWrapper","correct":"import { createWrapper } from 'souvlaki';"},{"note":"Specifically designed for creating wrappers from React Contexts. Ensure named import for this utility.","wrong":"import createContextWrapper from 'souvlaki';","symbol":"createContextWrapper","correct":"import { createContextWrapper } from 'souvlaki';"},{"note":"Example of a specific wrapper (if available) that might be imported from a subpath. Always check documentation for specific wrapper paths.","wrong":"import { ApolloWrapper } from 'souvlaki';","symbol":"ApolloWrapper","correct":"import { ApolloWrapper } from 'souvlaki/lib/apollo';"}],"quickstart":{"code":"import React, { createContext, useContext } from 'react';\nimport { render, screen } from '@testing-library/react';\nimport { createWrapper, createContextWrapper } from 'souvlaki';\n\n// 1. Define a simple context\ninterface ThemeContextType { theme: string; toggleTheme: () => void; }\nconst ThemeContext = createContext<ThemeContextType | undefined>(undefined);\n\n// 2. Create a provider for the context\nconst ThemeProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {\n  const [theme, setTheme] = React.useState('light');\n  const toggleTheme = () => setTheme(prev => (prev === 'light' ? 'dark' : 'light'));\n  return (\n    <ThemeContext.Provider value={{ theme, toggleTheme }}>\n      {children}\n    </ThemeContext.Provider>\n  );\n};\n\n// 3. Create a component that consumes the context\nconst ThemeDisplay: React.FC = () => {\n  const context = useContext(ThemeContext);\n  if (!context) return null; // Should not happen in a correctly wrapped test\n  return (\n    <div>\n      <span data-testid=\"current-theme\">Current Theme: {context.theme}</span>\n      <button onClick={context.toggleTheme}>Toggle Theme</button>\n    </div>\n  );\n};\n\n// 4. Create a Souvlaki wrapper for the ThemeProvider\nconst themeSouvlakiWrapper = createContextWrapper(ThemeContext, ThemeProvider);\n\n// 5. Use the wrapper in a test with React Testing Library\ndescribe('ThemeDisplay with Souvlaki wrapper', () => {\n  it('displays the default theme and allows toggling', () => {\n    // Use the souvlaki wrapper directly in render options\n    render(<ThemeDisplay />, { wrapper: themeSouvlakiWrapper });\n\n    expect(screen.getByTestId('current-theme')).toHaveTextContent('Current Theme: light');\n\n    screen.getByRole('button', { name: /toggle theme/i }).click();\n\n    expect(screen.getByTestId('current-theme')).toHaveTextContent('Current Theme: dark');\n  });\n\n  it('can compose multiple wrappers', () => {\n    // Imagine another provider, e.g., for user authentication\n    const AuthContext = createContext<{ user: string }>({ user: 'Guest' });\n    const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => (\n      <AuthContext.Provider value={{ user: 'TestUser' }}>{children}</AuthContext.Provider>\n    );\n    const authSouvlakiWrapper = createContextWrapper(AuthContext, AuthProvider);\n\n    // Compose wrappers using createWrapper\n    const CombinedWrapper = createWrapper(themeSouvlakiWrapper, authSouvlakiWrapper);\n\n    render(<ThemeDisplay />, { wrapper: CombinedWrapper });\n    expect(screen.getByTestId('current-theme')).toHaveTextContent('Current Theme: light');\n  });\n});","lang":"typescript","description":"Demonstrates how to use `createContextWrapper` to provide a React context to a component under test, and how to compose multiple wrappers with `createWrapper` for complex setups."},"warnings":[{"fix":"Review the project's GitHub page for recent activity or forks if encountering compatibility issues with newer React versions. Consider contributing or seeking alternative solutions if actively developing with bleeding-edge React features.","message":"Souvlaki (v0.3.1) has not been updated in a couple of years, though the author states it's actively used and considered 'finished'. This means it might not receive updates for new React features or changes, potentially leading to compatibility issues with very recent React versions or ecosystem libraries.","severity":"gotcha","affected_versions":">=0.3.0"},{"fix":"Ensure a solid understanding of `@testing-library/react` principles. Souvlaki is an enhancement for provider management, not a full replacement for testing methodology.","message":"Souvlaki simplifies the *creation* and *composition* of wrappers for React Testing Library but does not replace the need to understand how React Testing Library's `render` and `screen` utilities work, or how to correctly interact with the DOM in tests.","severity":"gotcha","affected_versions":"*"}],"env_vars":null,"search_vec":"'0.3.1':65 'abstract':37 'activ':84 'altern':111 'apollo':55 'associ':42 'author':68 'away':38 'boilerpl':40 'cadenc':95 'cleaner':110 'combin':34 'complex':46 'compon':18,50 'compos':2,29 'consid':87 'context':23,58 'creat':32,114 'current':62 'custom':57,115 'design':13 'differenti':98 'direct':121 'doesn':77 'environ':48 'everi':123 'finish':75 'first':11 'function':117 'heavili':21 'impli':89 'javascript':139 'key':97 'less':74 'librari':12,138 'maintain':88,128 'manag':102 'manual':113 'multipl':25,104 'nest':119 'note':69 'offer':28,108 'often':41 'packag':60 'promot':126 'provid':26,105,120 'react':3,17,53,136 'readabl':130 'receiv':79 'redux':52 'regular':80 'releas':94 'reli':20 'render':116 'router':54 'set':44 'simplifi':15,100 'slow':93 'souvlaki':1,6 'stabl':91 'suit':132 'test':4,16,35,47,107,124,131,137 'therebi':125 'typescript':10,140 'typescript-first':9 'updat':81 'use':51,85,134 'util':30 'version':64 'wrapper':5,36","created_at":"2026-04-20T01:57:36.562489+00:00","updated_at":"2026-04-20T01:57:36.562489+00:00","problems":[{"fix":"Ensure you are wrapping your component with the correct Souvlaki wrapper (e.g., `createContextWrapper` or a composed `createWrapper`) when calling `render` from `@testing-library/react`. Pass the wrapper via the `wrapper` option in `render({ wrapper: MyWrapper })`.","cause":"A component under test is trying to access context values (e.g., `theme`) but the necessary provider has not been rendered in the test environment.","error":"TypeError: Cannot read properties of undefined (reading 'theme')"},{"fix":"Use Souvlaki's `createWrapper` to include a `BrowserRouter` (or appropriate router) wrapper in your test setup. For example, `createWrapper(routerWrapper, yourOtherWrapper)`. If Souvlaki provides specific router wrappers (e.g., `MemoryRouterWrapper`), use those.","cause":"This error typically occurs when testing a component that expects to be inside a React Router `BrowserRouter` (or similar router context), but the router wrapper is missing in the test setup.","error":"Invariant Violation: You should not use <Provider> outside a <BrowserRouter>."}],"ecosystem":"npm","meta_description":null,"install_score":null,"quickstart_score":null,"quickstart_tag":null,"pypi_latest":null,"cli_name":"","cli_version":null,"type":"library","homepage":null,"github":null,"docs":null,"changelog":null,"pypi":null,"npm":"https://www.npmjs.com/package/souvlaki","openapi_spec":null,"status_page":null,"smithery":null,"categories":["testing","web-framework"],"base_url":null,"auth_type":null,"provenance":{"verified_status":null,"verified_at":null,"last_verified":"2026-06-17","next_check":"2026-07-18","install_tag":null}}