219 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
			
		
		
	
	
			219 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
| /*
 | |
|  * Copyright 2025 coze-dev Authors
 | |
|  *
 | |
|  * Licensed under the Apache License, Version 2.0 (the "License");
 | |
|  * you may not use this file except in compliance with the License.
 | |
|  * You may obtain a copy of the License at
 | |
|  *
 | |
|  *     http://www.apache.org/licenses/LICENSE-2.0
 | |
|  *
 | |
|  * Unless required by applicable law or agreed to in writing, software
 | |
|  * distributed under the License is distributed on an "AS IS" BASIS,
 | |
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | |
|  * See the License for the specific language governing permissions and
 | |
|  * limitations under the License.
 | |
|  */
 | |
| 
 | |
| import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
 | |
| import { renderHook } from '@testing-library/react';
 | |
| 
 | |
| import {
 | |
|   useMediaQuery,
 | |
|   useCustomMediaQuery,
 | |
| } from '../../src/hooks/media-query';
 | |
| import {
 | |
|   ScreenRange,
 | |
|   SCREENS_TOKENS,
 | |
|   SCREENS_TOKENS_2,
 | |
| } from '../../src/constant';
 | |
| 
 | |
| describe('useCustomMediaQuery', () => {
 | |
|   // Save the original window.matchMedia
 | |
|   const originalMatchMedia = window.matchMedia;
 | |
| 
 | |
|   beforeEach(() => {
 | |
|     // Emulate window.matchMedia
 | |
|     window.matchMedia = vi.fn().mockImplementation(query => ({
 | |
|       matches: false,
 | |
|       media: query,
 | |
|       onchange: null,
 | |
|       addListener: vi.fn(), // Compatible with outdated API
 | |
|       removeListener: vi.fn(), // Compatible with outdated API
 | |
|       addEventListener: vi.fn(),
 | |
|       removeEventListener: vi.fn(),
 | |
|       dispatchEvent: vi.fn(),
 | |
|     }));
 | |
|   });
 | |
| 
 | |
|   afterEach(() => {
 | |
|     // Restore the original window.matchMedia
 | |
|     window.matchMedia = originalMatchMedia;
 | |
|     vi.resetAllMocks();
 | |
|   });
 | |
| 
 | |
|   it('should return false when media query does not match', () => {
 | |
|     // Set matchMedia to return false
 | |
|     window.matchMedia = vi.fn().mockImplementation(query => ({
 | |
|       matches: false,
 | |
|       media: query,
 | |
|       addEventListener: vi.fn(),
 | |
|       removeEventListener: vi.fn(),
 | |
|     }));
 | |
| 
 | |
|     const { result } = renderHook(() =>
 | |
|       useCustomMediaQuery({ rangeMinPx: '768px', rangeMaxPx: '1200px' }),
 | |
|     );
 | |
| 
 | |
|     expect(result.current).toBe(false);
 | |
|     expect(window.matchMedia).toHaveBeenCalledWith(
 | |
|       '(min-width: 768px) and (max-width: 1200px)',
 | |
|     );
 | |
|   });
 | |
| 
 | |
|   it('should return true when media query matches', () => {
 | |
|     // Set matchMedia to return true
 | |
|     window.matchMedia = vi.fn().mockImplementation(query => ({
 | |
|       matches: true,
 | |
|       media: query,
 | |
|       addEventListener: vi.fn(),
 | |
|       removeEventListener: vi.fn(),
 | |
|     }));
 | |
| 
 | |
|     const { result } = renderHook(() =>
 | |
|       useCustomMediaQuery({ rangeMinPx: '768px', rangeMaxPx: '1200px' }),
 | |
|     );
 | |
| 
 | |
|     expect(result.current).toBe(true);
 | |
|     expect(window.matchMedia).toHaveBeenCalledWith(
 | |
|       '(min-width: 768px) and (max-width: 1200px)',
 | |
|     );
 | |
|   });
 | |
| 
 | |
|   it('should handle only min width', () => {
 | |
|     window.matchMedia = vi.fn().mockImplementation(query => ({
 | |
|       matches: true,
 | |
|       media: query,
 | |
|       addEventListener: vi.fn(),
 | |
|       removeEventListener: vi.fn(),
 | |
|     }));
 | |
| 
 | |
|     const { result } = renderHook(() =>
 | |
|       useCustomMediaQuery({ rangeMinPx: '768px' }),
 | |
|     );
 | |
| 
 | |
|     expect(result.current).toBe(true);
 | |
|     expect(window.matchMedia).toHaveBeenCalledWith('(min-width: 768px)');
 | |
|   });
 | |
| 
 | |
|   it('should handle only max width', () => {
 | |
|     window.matchMedia = vi.fn().mockImplementation(query => ({
 | |
|       matches: true,
 | |
|       media: query,
 | |
|       addEventListener: vi.fn(),
 | |
|       removeEventListener: vi.fn(),
 | |
|     }));
 | |
| 
 | |
|     const { result } = renderHook(() =>
 | |
|       useCustomMediaQuery({ rangeMaxPx: '1200px' }),
 | |
|     );
 | |
| 
 | |
|     expect(result.current).toBe(true);
 | |
|     expect(window.matchMedia).toHaveBeenCalledWith('(max-width: 1200px)');
 | |
|   });
 | |
| 
 | |
|   it('should update when media query changes', () => {
 | |
|     // Create a simulated MediaQueryList
 | |
|     const mediaQueryList = {
 | |
|       matches: false,
 | |
|       media: '(min-width: 768px)',
 | |
|       addEventListener: vi.fn(),
 | |
|       removeEventListener: vi.fn(),
 | |
|     };
 | |
| 
 | |
|     // Emulate window.matchMedia returns our mediaQueryList
 | |
|     window.matchMedia = vi.fn().mockReturnValue(mediaQueryList);
 | |
| 
 | |
|     const { result, rerender } = renderHook(() =>
 | |
|       useCustomMediaQuery({ rangeMinPx: '768px' }),
 | |
|     );
 | |
| 
 | |
|     // The initial state is false
 | |
|     expect(result.current).toBe(false);
 | |
| 
 | |
|     // Find the registered event handler
 | |
|     const eventListenerCall = mediaQueryList.addEventListener.mock.calls[0];
 | |
|     const eventType = eventListenerCall[0];
 | |
|     const handler = eventListenerCall[1];
 | |
| 
 | |
|     // Confirm that the event type is'change'
 | |
|     expect(eventType).toBe('change');
 | |
| 
 | |
|     // Simulate media query changes
 | |
|     mediaQueryList.matches = true;
 | |
|     handler();
 | |
| 
 | |
|     // Render the hook again to get the updated value
 | |
|     rerender();
 | |
| 
 | |
|     // It should be true now
 | |
|     expect(result.current).toBe(true);
 | |
|   });
 | |
| });
 | |
| 
 | |
| describe('useMediaQuery', () => {
 | |
|   // Save the original window.matchMedia
 | |
|   const originalMatchMedia = window.matchMedia;
 | |
| 
 | |
|   beforeEach(() => {
 | |
|     // Emulate window.matchMedia
 | |
|     window.matchMedia = vi.fn().mockImplementation(query => ({
 | |
|       matches: false,
 | |
|       media: query,
 | |
|       addEventListener: vi.fn(),
 | |
|       removeEventListener: vi.fn(),
 | |
|     }));
 | |
|   });
 | |
| 
 | |
|   afterEach(() => {
 | |
|     // Restore the original window.matchMedia
 | |
|     window.matchMedia = originalMatchMedia;
 | |
|     vi.resetAllMocks();
 | |
|   });
 | |
| 
 | |
|   it('should use correct screen tokens for min and max ranges', () => {
 | |
|     renderHook(() =>
 | |
|       useMediaQuery({ rangeMin: ScreenRange.MD, rangeMax: ScreenRange.LG }),
 | |
|     );
 | |
| 
 | |
|     expect(window.matchMedia).toHaveBeenCalledWith(
 | |
|       `(min-width: ${SCREENS_TOKENS[ScreenRange.MD]}) and (max-width: ${
 | |
|         SCREENS_TOKENS[ScreenRange.LG]
 | |
|       })`,
 | |
|     );
 | |
|   });
 | |
| 
 | |
|   it('should handle only min range', () => {
 | |
|     renderHook(() => useMediaQuery({ rangeMin: ScreenRange.MD }));
 | |
| 
 | |
|     expect(window.matchMedia).toHaveBeenCalledWith(
 | |
|       `(min-width: ${SCREENS_TOKENS[ScreenRange.MD]})`,
 | |
|     );
 | |
|   });
 | |
| 
 | |
|   it('should handle only max range', () => {
 | |
|     renderHook(() => useMediaQuery({ rangeMax: ScreenRange.LG }));
 | |
| 
 | |
|     expect(window.matchMedia).toHaveBeenCalledWith(
 | |
|       `(max-width: ${SCREENS_TOKENS[ScreenRange.LG]})`,
 | |
|     );
 | |
|   });
 | |
| 
 | |
|   it('should use tokens from SCREENS_TOKENS_2 when available', () => {
 | |
|     renderHook(() => useMediaQuery({ rangeMin: ScreenRange.XL1_5 }));
 | |
| 
 | |
|     expect(window.matchMedia).toHaveBeenCalledWith(
 | |
|       `(min-width: ${SCREENS_TOKENS_2[ScreenRange.XL1_5]})`,
 | |
|     );
 | |
|   });
 | |
| });
 |