@rakeyshgidwani/roger-ui-bank-theme-stan-design 0.1.7 → 0.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +1 -1
- package/dist/index.d.ts +0 -5
- package/dist/index.esm.js +3 -11
- package/dist/index.js +3 -11
- package/dist/styles.css +1 -1
- package/package.json +1 -1
- package/src/index.ts +5 -15
- package/dist/setupTests.d.ts +0 -124
- package/dist/setupTests.esm.js +0 -122
- package/dist/setupTests.js +0 -122
- package/src/setupTests.ts +0 -124
- package/src/stories/README.md +0 -39
- package/src/stories/components/ThemeDebugger.tsx +0 -143
- package/src/stories/index.ts +0 -29
- package/src/stories/storybook-theme-imports.css +0 -51
- package/src/test-utils/index.ts +0 -7
- package/src/test-utils/theme-testing.tsx +0 -219
- package/src/testing/test-automation.ts +0 -627
- package/src/testing/test-utils.tsx +0 -367
package/src/setupTests.ts
DELETED
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
import '@testing-library/jest-dom';
|
|
2
|
-
|
|
3
|
-
// Mock localStorage for Jest environment
|
|
4
|
-
const localStorageMock = {
|
|
5
|
-
getItem: jest.fn(),
|
|
6
|
-
setItem: jest.fn(),
|
|
7
|
-
removeItem: jest.fn(),
|
|
8
|
-
clear: jest.fn(),
|
|
9
|
-
length: 0,
|
|
10
|
-
key: jest.fn(),
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
Object.defineProperty(window, 'localStorage', {
|
|
14
|
-
value: localStorageMock,
|
|
15
|
-
writable: true,
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
// Mock sessionStorage for Jest environment
|
|
19
|
-
const sessionStorageMock = {
|
|
20
|
-
getItem: jest.fn(),
|
|
21
|
-
setItem: jest.fn(),
|
|
22
|
-
removeItem: jest.fn(),
|
|
23
|
-
clear: jest.fn(),
|
|
24
|
-
length: 0,
|
|
25
|
-
key: jest.fn(),
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
Object.defineProperty(window, 'sessionStorage', {
|
|
29
|
-
value: sessionStorageMock,
|
|
30
|
-
writable: true,
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
// Mock performance API for Jest environment
|
|
34
|
-
Object.defineProperty(window, 'performance', {
|
|
35
|
-
value: {
|
|
36
|
-
now: jest.fn(() => Date.now()),
|
|
37
|
-
memory: {
|
|
38
|
-
usedJSHeapSize: 1000000,
|
|
39
|
-
totalJSHeapSize: 2000000,
|
|
40
|
-
jsHeapSizeLimit: 3000000,
|
|
41
|
-
},
|
|
42
|
-
},
|
|
43
|
-
writable: true,
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
// Mock ResizeObserver for Jest environment
|
|
47
|
-
global.ResizeObserver = jest.fn().mockImplementation(() => ({
|
|
48
|
-
observe: jest.fn(),
|
|
49
|
-
unobserve: jest.fn(),
|
|
50
|
-
disconnect: jest.fn(),
|
|
51
|
-
}));
|
|
52
|
-
|
|
53
|
-
// Mock IntersectionObserver for Jest environment
|
|
54
|
-
global.IntersectionObserver = jest.fn().mockImplementation(() => ({
|
|
55
|
-
observe: jest.fn(),
|
|
56
|
-
unobserve: jest.fn(),
|
|
57
|
-
disconnect: jest.fn(),
|
|
58
|
-
}));
|
|
59
|
-
|
|
60
|
-
// Mock React 18 createRoot for Jest environment
|
|
61
|
-
const mockCreateRoot = jest.fn(() => ({
|
|
62
|
-
render: jest.fn(),
|
|
63
|
-
unmount: jest.fn(),
|
|
64
|
-
}));
|
|
65
|
-
|
|
66
|
-
Object.defineProperty(window, 'createRoot', {
|
|
67
|
-
value: mockCreateRoot,
|
|
68
|
-
writable: true,
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
// Suppress console warnings for expected test behavior
|
|
72
|
-
const originalWarn = console.warn;
|
|
73
|
-
const originalError = console.error;
|
|
74
|
-
|
|
75
|
-
beforeAll(() => {
|
|
76
|
-
// Suppress specific warnings that are expected in tests
|
|
77
|
-
console.warn = jest.fn((...args) => {
|
|
78
|
-
const message = args[0];
|
|
79
|
-
if (
|
|
80
|
-
typeof message === 'string' && (
|
|
81
|
-
message.includes('Failed to read theme from storage') ||
|
|
82
|
-
message.includes('Failed to store theme preference') ||
|
|
83
|
-
message.includes('Failed to read system theme preference from storage')
|
|
84
|
-
)
|
|
85
|
-
) {
|
|
86
|
-
return; // Suppress expected storage warnings
|
|
87
|
-
}
|
|
88
|
-
originalWarn(...args);
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
// Suppress specific errors that are expected in tests
|
|
92
|
-
console.error = jest.fn((...args) => {
|
|
93
|
-
const message = args[0];
|
|
94
|
-
if (
|
|
95
|
-
typeof message === 'string' && (
|
|
96
|
-
message.includes('Warning: An update to ThemeProvider inside a test was not wrapped in act') ||
|
|
97
|
-
message.includes('createRoot') ||
|
|
98
|
-
message.includes('Target container is not a DOM element')
|
|
99
|
-
)
|
|
100
|
-
) {
|
|
101
|
-
return; // Suppress expected React act warnings and createRoot errors
|
|
102
|
-
}
|
|
103
|
-
originalError(...args);
|
|
104
|
-
});
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
afterAll(() => {
|
|
108
|
-
// Restore original console methods
|
|
109
|
-
console.warn = originalWarn;
|
|
110
|
-
console.error = originalError;
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
// Reset mocks before each test
|
|
114
|
-
beforeEach(() => {
|
|
115
|
-
localStorageMock.getItem.mockClear();
|
|
116
|
-
localStorageMock.setItem.mockClear();
|
|
117
|
-
localStorageMock.removeItem.mockClear();
|
|
118
|
-
localStorageMock.clear.mockClear();
|
|
119
|
-
|
|
120
|
-
sessionStorageMock.getItem.mockClear();
|
|
121
|
-
sessionStorageMock.setItem.mockClear();
|
|
122
|
-
sessionStorageMock.removeItem.mockClear();
|
|
123
|
-
sessionStorageMock.clear.mockClear();
|
|
124
|
-
});
|
package/src/stories/README.md
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
# Storybook Stories
|
|
2
|
-
|
|
3
|
-
This directory contains all the Storybook stories for the Roger UI Bank design system.
|
|
4
|
-
|
|
5
|
-
## Structure
|
|
6
|
-
|
|
7
|
-
- `components/` - Component stories organized by category
|
|
8
|
-
- `ui/` - Basic UI component stories
|
|
9
|
-
- `layouts/` - Layout component stories
|
|
10
|
-
- `feedback/` - Feedback component stories
|
|
11
|
-
- `navigation/` - Navigation component stories
|
|
12
|
-
- `overlay/` - Overlay component stories
|
|
13
|
-
- `data-display/` - Data display component stories
|
|
14
|
-
- `themes/` - Theme documentation and examples
|
|
15
|
-
- `decorators/` - Story decorators for common functionality
|
|
16
|
-
|
|
17
|
-
## Usage
|
|
18
|
-
|
|
19
|
-
1. Start Storybook: `npm run storybook`
|
|
20
|
-
2. Navigate to http://localhost:6006
|
|
21
|
-
3. Use the theme switcher in the toolbar to see different themes
|
|
22
|
-
4. Explore component variations and documentation
|
|
23
|
-
|
|
24
|
-
## Adding New Stories
|
|
25
|
-
|
|
26
|
-
1. Create a new story file in the appropriate category
|
|
27
|
-
2. Import the component and create stories
|
|
28
|
-
3. Add theme decorator for multi-theme support
|
|
29
|
-
4. Include comprehensive documentation
|
|
30
|
-
5. Test with all available themes
|
|
31
|
-
|
|
32
|
-
## Theme Support
|
|
33
|
-
|
|
34
|
-
All components support three themes:
|
|
35
|
-
- **Stan Design** - Modern, professional design
|
|
36
|
-
- **Enterprise** - Corporate, business-focused design
|
|
37
|
-
- **Harvey Creative** - Creative, vibrant design
|
|
38
|
-
|
|
39
|
-
Use the theme decorator to ensure proper theme integration in your stories.
|
|
@@ -1,143 +0,0 @@
|
|
|
1
|
-
import React, { useEffect, useState } from 'react';
|
|
2
|
-
import { useTheme } from '../../themes';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Theme Debugger Component for Storybook
|
|
6
|
-
* Shows current theme state and CSS variables for debugging
|
|
7
|
-
*/
|
|
8
|
-
export const ThemeDebugger: React.FC = () => {
|
|
9
|
-
const { currentTheme, currentThemeConfig, availableThemes } = useTheme();
|
|
10
|
-
const [cssVariables, setCssVariables] = useState<Record<string, string>>({});
|
|
11
|
-
const [isVisible, setIsVisible] = useState(false);
|
|
12
|
-
|
|
13
|
-
// Extract CSS variables from document root
|
|
14
|
-
useEffect(() => {
|
|
15
|
-
const extractCSSVariables = () => {
|
|
16
|
-
const root = document.documentElement;
|
|
17
|
-
const variables: Record<string, string> = {};
|
|
18
|
-
|
|
19
|
-
// Get all CSS custom properties
|
|
20
|
-
const styles = getComputedStyle(root);
|
|
21
|
-
|
|
22
|
-
// Method 1: Try to get all CSS properties
|
|
23
|
-
try {
|
|
24
|
-
for (let i = 0; i < styles.length; i++) {
|
|
25
|
-
const property = styles[i];
|
|
26
|
-
if (property.startsWith('--cs-')) {
|
|
27
|
-
variables[property] = styles.getPropertyValue(property);
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
} catch (error) {
|
|
31
|
-
console.warn('Could not iterate through styles:', error);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
// Method 2: Try to get specific known CSS variables
|
|
35
|
-
const knownVariables = [
|
|
36
|
-
'--cs-primary-500', '--cs-secondary-500', '--cs-success', '--cs-warning', '--cs-error', '--cs-info',
|
|
37
|
-
'--cs-text-primary', '--cs-text-secondary', '--cs-surface-bg', '--cs-border',
|
|
38
|
-
'--cs-fonts-primary-family', '--cs-fonts-primary-sizes-md', '--cs-spacing-4'
|
|
39
|
-
];
|
|
40
|
-
|
|
41
|
-
knownVariables.forEach(varName => {
|
|
42
|
-
try {
|
|
43
|
-
const value = styles.getPropertyValue(varName);
|
|
44
|
-
if (value && value.trim() !== '') {
|
|
45
|
-
variables[varName] = value;
|
|
46
|
-
}
|
|
47
|
-
} catch (error) {
|
|
48
|
-
// Variable doesn't exist
|
|
49
|
-
}
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
// Method 3: Check if variables are set via inline styles
|
|
53
|
-
const inlineVars = root.style.cssText.match(/--cs-[^:]+:[^;]+/g) || [];
|
|
54
|
-
inlineVars.forEach(varDeclaration => {
|
|
55
|
-
const [name, value] = varDeclaration.split(':');
|
|
56
|
-
if (name && value) {
|
|
57
|
-
variables[name.trim()] = value.trim();
|
|
58
|
-
}
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
console.log('Extracted CSS variables:', variables);
|
|
62
|
-
setCssVariables(variables);
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
extractCSSVariables();
|
|
66
|
-
|
|
67
|
-
// Listen for theme changes
|
|
68
|
-
const handleThemeChange = () => {
|
|
69
|
-
setTimeout(extractCSSVariables, 200); // Increased delay to ensure CSS is updated
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
window.addEventListener('themeChange', handleThemeChange);
|
|
73
|
-
|
|
74
|
-
// Also check periodically for changes
|
|
75
|
-
const interval = setInterval(extractCSSVariables, 1000);
|
|
76
|
-
|
|
77
|
-
return () => {
|
|
78
|
-
window.removeEventListener('themeChange', handleThemeChange);
|
|
79
|
-
clearInterval(interval);
|
|
80
|
-
};
|
|
81
|
-
}, [currentTheme]);
|
|
82
|
-
|
|
83
|
-
if (!isVisible) {
|
|
84
|
-
return (
|
|
85
|
-
<button
|
|
86
|
-
onClick={() => setIsVisible(true)}
|
|
87
|
-
className="fixed bottom-4 right-4 bg-blue-600 text-white px-3 py-2 rounded-lg text-sm z-50"
|
|
88
|
-
>
|
|
89
|
-
🐛 Debug Theme
|
|
90
|
-
</button>
|
|
91
|
-
);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
return (
|
|
95
|
-
<div className="fixed bottom-4 right-4 bg-white dark:bg-gray-800 border border-gray-300 dark:border-gray-600 rounded-lg p-4 max-w-md max-h-96 overflow-auto shadow-lg z-50">
|
|
96
|
-
<div className="flex items-center justify-between mb-3">
|
|
97
|
-
<h3 className="font-semibold text-gray-900 dark:text-white">Theme Debugger</h3>
|
|
98
|
-
<button
|
|
99
|
-
onClick={() => setIsVisible(false)}
|
|
100
|
-
className="text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200"
|
|
101
|
-
>
|
|
102
|
-
✕
|
|
103
|
-
</button>
|
|
104
|
-
</div>
|
|
105
|
-
|
|
106
|
-
<div className="space-y-3 text-sm">
|
|
107
|
-
<div>
|
|
108
|
-
<strong>Current Theme:</strong> {currentTheme}
|
|
109
|
-
</div>
|
|
110
|
-
|
|
111
|
-
<div>
|
|
112
|
-
<strong>Available Themes:</strong> {availableThemes.join(', ')}
|
|
113
|
-
</div>
|
|
114
|
-
|
|
115
|
-
{currentThemeConfig && (
|
|
116
|
-
<div>
|
|
117
|
-
<strong>Theme Config:</strong>
|
|
118
|
-
<pre className="mt-1 p-2 bg-gray-100 dark:bg-gray-700 rounded text-xs overflow-auto max-h-20">
|
|
119
|
-
{JSON.stringify({
|
|
120
|
-
name: currentThemeConfig.meta?.name,
|
|
121
|
-
description: currentThemeConfig.meta?.description,
|
|
122
|
-
category: currentThemeConfig.meta?.category,
|
|
123
|
-
primaryColor: currentThemeConfig.colors?.primary?.[500],
|
|
124
|
-
fontFamily: currentThemeConfig.fonts?.primary?.family
|
|
125
|
-
}, null, 2)}
|
|
126
|
-
</pre>
|
|
127
|
-
</div>
|
|
128
|
-
)}
|
|
129
|
-
|
|
130
|
-
<div>
|
|
131
|
-
<strong>CSS Variables ({Object.keys(cssVariables).length}):</strong>
|
|
132
|
-
<div className="mt-1 max-h-32 overflow-auto">
|
|
133
|
-
{Object.entries(cssVariables).map(([variable, value]) => (
|
|
134
|
-
<div key={variable} className="text-xs font-mono">
|
|
135
|
-
<span className="text-blue-600">{variable}:</span> {value}
|
|
136
|
-
</div>
|
|
137
|
-
))}
|
|
138
|
-
</div>
|
|
139
|
-
</div>
|
|
140
|
-
</div>
|
|
141
|
-
</div>
|
|
142
|
-
);
|
|
143
|
-
};
|
package/src/stories/index.ts
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
// Stories index file
|
|
2
|
-
// Export all story-related utilities and decorators
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
// Theme stories
|
|
7
|
-
export * from './themes/theme-showcase.stories';
|
|
8
|
-
export * from './themes/theme-documentation.stories';
|
|
9
|
-
|
|
10
|
-
// Core UI Component Stories
|
|
11
|
-
export * from './components/ui/button.stories';
|
|
12
|
-
export * from './components/ui/card.stories';
|
|
13
|
-
export * from './components/ui/input.stories';
|
|
14
|
-
export * from './components/ui/mobile-input.stories';
|
|
15
|
-
export * from './components/ui/checkbox.stories';
|
|
16
|
-
export * from './components/ui/badge.stories';
|
|
17
|
-
export * from './components/ui/label.stories';
|
|
18
|
-
|
|
19
|
-
// Theme System Component Stories
|
|
20
|
-
|
|
21
|
-
export * from './components/ui/theme-preview.stories';
|
|
22
|
-
export * from './components/ui/color-preview.stories';
|
|
23
|
-
export * from './components/ui/font-preview.stories';
|
|
24
|
-
|
|
25
|
-
// Theme utilities
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
// This file will be expanded as we add more stories
|
|
29
|
-
// and utilities for the design system
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
/* Storybook Theme CSS Imports - Stan Design Only */
|
|
2
|
-
/* This file ensures Stan Design theme styles are available in Storybook */
|
|
3
|
-
|
|
4
|
-
/* Import Stan Design theme styles directly (bypassing theme index to avoid Harvey theme) */
|
|
5
|
-
@import '../styles/themes/stan-design.css';
|
|
6
|
-
|
|
7
|
-
/* Import additional theme-related styles (excluding theme.css to avoid Harvey import) */
|
|
8
|
-
@import '../styles/base/fonts.css';
|
|
9
|
-
|
|
10
|
-
/* Ensure Stan Design theme variables are available in Storybook iframe */
|
|
11
|
-
:root {
|
|
12
|
-
/* Stan Design theme variables for Storybook */
|
|
13
|
-
--cs-theme-active: 'stan-design';
|
|
14
|
-
--cs-theme-available: 'stan-design';
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
/* Apply Stan Design theme globally to all Storybook content */
|
|
18
|
-
body {
|
|
19
|
-
background-color: var(--cs-colors-surface-background, #f8fafc);
|
|
20
|
-
color: var(--cs-colors-text-primary, #0f172a);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
/* Ensure all stories inherit the Stan Design theme */
|
|
24
|
-
#storybook-panel-root,
|
|
25
|
-
#storybook-preview-wrapper,
|
|
26
|
-
#storybook-preview-iframe {
|
|
27
|
-
background-color: var(--cs-colors-surface-background, #f8fafc) !important;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/* Dark mode overrides for Storybook */
|
|
31
|
-
.dark body {
|
|
32
|
-
background-color: var(--cs-colors-surface-background, #0f172a) !important;
|
|
33
|
-
color: var(--cs-colors-text-primary, #f8fafc) !important;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
.dark #storybook-panel-root,
|
|
37
|
-
.dark #storybook-preview-wrapper,
|
|
38
|
-
.dark #storybook-preview-iframe {
|
|
39
|
-
background-color: var(--cs-colors-surface-background, #0f172a) !important;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/* Stan Design theme overrides for Storybook */
|
|
43
|
-
[data-theme="stan-design"] {
|
|
44
|
-
/* Stan Design theme specific styles */
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/* Storybook-specific theme indicator */
|
|
48
|
-
[data-storybook-theme="stan-design"] {
|
|
49
|
-
/* Visual indicator that Stan Design theme is active in Storybook */
|
|
50
|
-
position: relative;
|
|
51
|
-
}
|
package/src/test-utils/index.ts
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
// Test utilities for theme-aware testing
|
|
2
|
-
export * from './theme-testing';
|
|
3
|
-
|
|
4
|
-
// Re-export common testing utilities
|
|
5
|
-
export { render, screen, fireEvent, waitFor, act } from '@testing-library/react';
|
|
6
|
-
export { userEvent } from '@testing-library/user-event';
|
|
7
|
-
export type { RenderResult, RenderOptions } from '@testing-library/react';
|
|
@@ -1,219 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { render, RenderOptions, RenderResult } from '@testing-library/react';
|
|
3
|
-
import { ThemeProvider } from '../themes/ThemeProvider';
|
|
4
|
-
import { defaultThemes } from '../themes/base-themes';
|
|
5
|
-
import type { MultiThemeConfig } from '../themes/types';
|
|
6
|
-
|
|
7
|
-
// Mock window.matchMedia for Jest environment
|
|
8
|
-
Object.defineProperty(window, 'matchMedia', {
|
|
9
|
-
writable: true,
|
|
10
|
-
value: jest.fn().mockImplementation(query => ({
|
|
11
|
-
matches: false,
|
|
12
|
-
media: query,
|
|
13
|
-
onchange: null,
|
|
14
|
-
addListener: jest.fn(), // deprecated
|
|
15
|
-
removeListener: jest.fn(), // deprecated
|
|
16
|
-
addEventListener: jest.fn(),
|
|
17
|
-
removeEventListener: jest.fn(),
|
|
18
|
-
dispatchEvent: jest.fn(),
|
|
19
|
-
})),
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
// Test utilities for theme-aware component testing
|
|
23
|
-
|
|
24
|
-
export interface ThemeTestingOptions extends Omit<RenderOptions, 'wrapper'> {
|
|
25
|
-
theme?: string;
|
|
26
|
-
themes?: Record<string, MultiThemeConfig>;
|
|
27
|
-
persistTheme?: boolean;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Renders a component wrapped with ThemeProvider for testing
|
|
32
|
-
*/
|
|
33
|
-
export const renderWithTheme = (
|
|
34
|
-
component: React.ReactElement,
|
|
35
|
-
options: ThemeTestingOptions = {}
|
|
36
|
-
): RenderResult => {
|
|
37
|
-
const {
|
|
38
|
-
theme = 'stan-design',
|
|
39
|
-
themes = defaultThemes,
|
|
40
|
-
persistTheme = false,
|
|
41
|
-
...renderOptions
|
|
42
|
-
} = options;
|
|
43
|
-
|
|
44
|
-
const ThemeWrapper = ({ children }: { children: React.ReactNode }) => (
|
|
45
|
-
<ThemeProvider
|
|
46
|
-
defaultTheme={theme}
|
|
47
|
-
themes={themes}
|
|
48
|
-
persistTheme={persistTheme}
|
|
49
|
-
>
|
|
50
|
-
{children}
|
|
51
|
-
</ThemeProvider>
|
|
52
|
-
);
|
|
53
|
-
|
|
54
|
-
return render(component, {
|
|
55
|
-
wrapper: ThemeWrapper,
|
|
56
|
-
...renderOptions,
|
|
57
|
-
});
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* Renders a component in all available themes for comprehensive testing
|
|
62
|
-
*/
|
|
63
|
-
export const renderWithAllThemes = (
|
|
64
|
-
component: React.ReactElement,
|
|
65
|
-
options: Omit<ThemeTestingOptions, 'theme'> = {}
|
|
66
|
-
): Record<string, RenderResult> => {
|
|
67
|
-
const { themes = defaultThemes, ...renderOptions } = options;
|
|
68
|
-
const results: Record<string, RenderResult> = {};
|
|
69
|
-
|
|
70
|
-
Object.keys(themes).forEach(themeName => {
|
|
71
|
-
// Create a unique container for each theme to avoid conflicts
|
|
72
|
-
const container = document.createElement('div');
|
|
73
|
-
container.id = `theme-test-${themeName}`;
|
|
74
|
-
document.body.appendChild(container);
|
|
75
|
-
|
|
76
|
-
results[themeName] = render(component, {
|
|
77
|
-
container,
|
|
78
|
-
wrapper: ({ children }) => (
|
|
79
|
-
<ThemeProvider
|
|
80
|
-
defaultTheme={themeName}
|
|
81
|
-
themes={themes}
|
|
82
|
-
persistTheme={false}
|
|
83
|
-
>
|
|
84
|
-
{children}
|
|
85
|
-
</ThemeProvider>
|
|
86
|
-
),
|
|
87
|
-
...renderOptions,
|
|
88
|
-
});
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
return results;
|
|
92
|
-
};
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* Cleanup function to remove theme test containers
|
|
96
|
-
*/
|
|
97
|
-
export const cleanupThemeTests = (): void => {
|
|
98
|
-
const containers = document.querySelectorAll('[id^="theme-test-"]');
|
|
99
|
-
containers.forEach(container => {
|
|
100
|
-
container.remove();
|
|
101
|
-
});
|
|
102
|
-
};
|
|
103
|
-
|
|
104
|
-
/**
|
|
105
|
-
* Test helper to switch themes during testing
|
|
106
|
-
*/
|
|
107
|
-
export const createThemeSwitcher = (initialTheme: string = 'stan-design') => {
|
|
108
|
-
let currentTheme = initialTheme;
|
|
109
|
-
|
|
110
|
-
return {
|
|
111
|
-
getCurrentTheme: () => currentTheme,
|
|
112
|
-
switchTo: (newTheme: string) => {
|
|
113
|
-
currentTheme = newTheme;
|
|
114
|
-
return currentTheme;
|
|
115
|
-
},
|
|
116
|
-
renderWithCurrentTheme: (component: React.ReactElement, options: Omit<ThemeTestingOptions, 'theme'> = {}) => {
|
|
117
|
-
return renderWithTheme(component, { theme: currentTheme, ...options });
|
|
118
|
-
}
|
|
119
|
-
};
|
|
120
|
-
};
|
|
121
|
-
|
|
122
|
-
/**
|
|
123
|
-
* Helper to test theme-specific styles and properties
|
|
124
|
-
*/
|
|
125
|
-
export const getThemeStyles = (themeName: string, themes = defaultThemes) => {
|
|
126
|
-
const theme = themes[themeName];
|
|
127
|
-
if (!theme) {
|
|
128
|
-
throw new Error(`Theme '${themeName}' not found in provided themes`);
|
|
129
|
-
}
|
|
130
|
-
return theme;
|
|
131
|
-
};
|
|
132
|
-
|
|
133
|
-
/**
|
|
134
|
-
* Helper to test CSS custom properties applied by themes
|
|
135
|
-
*/
|
|
136
|
-
export const getThemeCSSVariables = (element: Element): Record<string, string> => {
|
|
137
|
-
const computedStyle = window.getComputedStyle(element);
|
|
138
|
-
const cssVariables: Record<string, string> = {};
|
|
139
|
-
|
|
140
|
-
// Get all CSS custom properties (variables starting with --)
|
|
141
|
-
for (let i = 0; i < computedStyle.length; i++) {
|
|
142
|
-
const property = computedStyle[i];
|
|
143
|
-
if (property.startsWith('--')) {
|
|
144
|
-
cssVariables[property] = computedStyle.getPropertyValue(property).trim();
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
return cssVariables;
|
|
149
|
-
};
|
|
150
|
-
|
|
151
|
-
/**
|
|
152
|
-
* Helper to wait for theme transitions to complete
|
|
153
|
-
*/
|
|
154
|
-
export const waitForThemeTransition = async (duration: number = 300): Promise<void> => {
|
|
155
|
-
return new Promise(resolve => {
|
|
156
|
-
setTimeout(resolve, duration);
|
|
157
|
-
});
|
|
158
|
-
};
|
|
159
|
-
|
|
160
|
-
/**
|
|
161
|
-
* Mock localStorage for theme persistence testing
|
|
162
|
-
*/
|
|
163
|
-
export const createThemeStorageMock = () => {
|
|
164
|
-
const storage: Record<string, string> = {};
|
|
165
|
-
|
|
166
|
-
return {
|
|
167
|
-
getItem: jest.fn((key: string) => storage[key] || null),
|
|
168
|
-
setItem: jest.fn((key: string, value: string) => {
|
|
169
|
-
storage[key] = value;
|
|
170
|
-
}),
|
|
171
|
-
removeItem: jest.fn((key: string) => {
|
|
172
|
-
delete storage[key];
|
|
173
|
-
}),
|
|
174
|
-
clear: jest.fn(() => {
|
|
175
|
-
Object.keys(storage).forEach(key => delete storage[key]);
|
|
176
|
-
}),
|
|
177
|
-
get storage() {
|
|
178
|
-
return { ...storage };
|
|
179
|
-
}
|
|
180
|
-
};
|
|
181
|
-
};
|
|
182
|
-
|
|
183
|
-
/**
|
|
184
|
-
* Mock matchMedia for responsive and system theme testing
|
|
185
|
-
*/
|
|
186
|
-
export const createMatchMediaMock = (matches: boolean = false) => {
|
|
187
|
-
return jest.fn().mockImplementation((query: string) => ({
|
|
188
|
-
matches,
|
|
189
|
-
media: query,
|
|
190
|
-
onchange: null,
|
|
191
|
-
addListener: jest.fn(),
|
|
192
|
-
removeListener: jest.fn(),
|
|
193
|
-
addEventListener: jest.fn(),
|
|
194
|
-
removeEventListener: jest.fn(),
|
|
195
|
-
dispatchEvent: jest.fn(),
|
|
196
|
-
}));
|
|
197
|
-
};
|
|
198
|
-
|
|
199
|
-
/**
|
|
200
|
-
* Test themes for consistent testing across all theme tests
|
|
201
|
-
*/
|
|
202
|
-
export const getTestThemes = () => Object.keys(defaultThemes);
|
|
203
|
-
|
|
204
|
-
/**
|
|
205
|
-
* Helper to test theme contrast and accessibility
|
|
206
|
-
*/
|
|
207
|
-
export const getThemeContrastInfo = (themeName: string, themes = defaultThemes) => {
|
|
208
|
-
const theme = themes[themeName];
|
|
209
|
-
if (!theme) {
|
|
210
|
-
throw new Error(`Theme '${themeName}' not found`);
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
return {
|
|
214
|
-
primaryColor: theme.colors.primary[500],
|
|
215
|
-
backgroundColor: theme.colors.text.primary,
|
|
216
|
-
textColor: theme.colors.text.primary,
|
|
217
|
-
borderColor: theme.colors.surface.border,
|
|
218
|
-
};
|
|
219
|
-
};
|