|
1 | 1 | import React from 'react'; |
2 | 2 |
|
3 | | -import { act, renderHook } from '@testing-library/react'; |
| 3 | +import { act, render, renderHook } from '@testing-library/react'; |
4 | 4 |
|
5 | 5 | import { isExtension, isMobile } from 'lib/platform'; |
6 | 6 |
|
7 | | -import { AppEnvProvider, useAppEnv, WindowType, IS_DEV_ENV, onboardingUrls, openInFullPage } from './env'; |
| 7 | +import { |
| 8 | + AppEnvProvider, |
| 9 | + OpenInFullPage, |
| 10 | + useAppEnv, |
| 11 | + WindowType, |
| 12 | + IS_DEV_ENV, |
| 13 | + onboardingUrls, |
| 14 | + openInFullPage |
| 15 | +} from './env'; |
8 | 16 |
|
9 | 17 | // Mock lib/platform |
10 | 18 | jest.mock('lib/platform', () => ({ |
@@ -236,4 +244,47 @@ describe('env', () => { |
236 | 244 | }); |
237 | 245 | }); |
238 | 246 | }); |
| 247 | + |
| 248 | + describe('OpenInFullPage', () => { |
| 249 | + const wrapper = ({ children }: { children: React.ReactNode }) => |
| 250 | + React.createElement(AppEnvProvider, { windowType: WindowType.Popup }, children); |
| 251 | + |
| 252 | + it('focuses an existing onboarding tab when one exists', async () => { |
| 253 | + mockTabsQuery.mockResolvedValueOnce([{ id: 42, url: 'chrome-extension://test/fullpage.html' }]); |
| 254 | + // Stub window.close so we can verify it's called for compact windows |
| 255 | + const closeSpy = jest.spyOn(window, 'close').mockImplementation(() => {}); |
| 256 | + render(React.createElement(OpenInFullPage), { wrapper }); |
| 257 | + // Wait for the async useLayoutEffect chain to settle |
| 258 | + await new Promise(r => setTimeout(r, 0)); |
| 259 | + expect(mockTabsUpdate).toHaveBeenCalledWith(42, { active: true }); |
| 260 | + closeSpy.mockRestore(); |
| 261 | + }); |
| 262 | + |
| 263 | + it('opens a new tab when no onboarding tab is found', async () => { |
| 264 | + mockTabsQuery.mockResolvedValueOnce([]); |
| 265 | + const closeSpy = jest.spyOn(window, 'close').mockImplementation(() => {}); |
| 266 | + render(React.createElement(OpenInFullPage), { wrapper }); |
| 267 | + await new Promise(r => setTimeout(r, 0)); |
| 268 | + expect(mockTabsCreate).toHaveBeenCalled(); |
| 269 | + closeSpy.mockRestore(); |
| 270 | + }); |
| 271 | + |
| 272 | + it('is a no-op outside extension context', async () => { |
| 273 | + mockIsExtension.mockReturnValue(false); |
| 274 | + const fullPageWrapper = ({ children }: { children: React.ReactNode }) => |
| 275 | + React.createElement(AppEnvProvider, { windowType: WindowType.FullPage }, children); |
| 276 | + render(React.createElement(OpenInFullPage), { wrapper: fullPageWrapper }); |
| 277 | + await new Promise(r => setTimeout(r, 0)); |
| 278 | + expect(mockTabsQuery).not.toHaveBeenCalled(); |
| 279 | + }); |
| 280 | + |
| 281 | + it('logs and recovers when browser APIs throw', async () => { |
| 282 | + const errSpy = jest.spyOn(console, 'error').mockImplementation(() => {}); |
| 283 | + mockTabsQuery.mockRejectedValueOnce(new Error('boom')); |
| 284 | + render(React.createElement(OpenInFullPage), { wrapper }); |
| 285 | + await new Promise(r => setTimeout(r, 0)); |
| 286 | + expect(errSpy).toHaveBeenCalledWith(expect.stringContaining('OpenInFullPage'), expect.any(Error)); |
| 287 | + errSpy.mockRestore(); |
| 288 | + }); |
| 289 | + }); |
239 | 290 | }); |
0 commit comments