110 lines
4.7 KiB
TypeScript
110 lines
4.7 KiB
TypeScript
import { describe, it, expect, vi } from 'vitest';
|
|
import type { Page, Locator } from 'playwright';
|
|
import { PlaywrightAuthSessionService } from '../../../packages/infrastructure/adapters/automation/auth/PlaywrightAuthSessionService';
|
|
import { AuthenticationState } from '../../../packages/domain/value-objects/AuthenticationState';
|
|
import { BrowserAuthenticationState } from '../../../packages/domain/value-objects/BrowserAuthenticationState';
|
|
import type { ILogger } from '../../../packages/application/ports/ILogger';
|
|
import type { Result } from '../../../packages/shared/result/Result';
|
|
import type { PlaywrightBrowserSession } from '../../../packages/infrastructure/adapters/automation/core/PlaywrightBrowserSession';
|
|
import type { SessionCookieStore } from '../../../packages/infrastructure/adapters/automation/auth/SessionCookieStore';
|
|
import type { IPlaywrightAuthFlow } from '../../../packages/infrastructure/adapters/automation/auth/PlaywrightAuthFlow';
|
|
|
|
describe('PlaywrightAuthSessionService.verifyPageAuthentication', () => {
|
|
function createService(deps: {
|
|
pageUrl: string;
|
|
hasLoginUi: boolean;
|
|
hasAuthUi: boolean;
|
|
cookieState: AuthenticationState;
|
|
}) {
|
|
const mockLogger: ILogger = {
|
|
debug: vi.fn(),
|
|
info: vi.fn(),
|
|
warn: vi.fn(),
|
|
error: vi.fn(),
|
|
};
|
|
|
|
const mockLocator: Locator = {
|
|
first: vi.fn().mockReturnThis(),
|
|
isVisible: vi.fn().mockImplementation(async () => deps.hasLoginUi),
|
|
} as unknown as Locator;
|
|
|
|
const mockPage: Page = {
|
|
url: vi.fn().mockReturnValue(deps.pageUrl),
|
|
locator: vi.fn().mockReturnValue(mockLocator),
|
|
} as unknown as Page;
|
|
|
|
const mockBrowserSession: PlaywrightBrowserSession = {
|
|
getPersistentContext: vi.fn().mockReturnValue(null),
|
|
getContext: vi.fn().mockReturnValue(null),
|
|
getPage: vi.fn().mockReturnValue(mockPage),
|
|
} as unknown as PlaywrightBrowserSession;
|
|
|
|
const mockCookieStore: SessionCookieStore = {
|
|
read: vi.fn().mockResolvedValue({
|
|
cookies: [{ name: 'XSESSIONID', value: 'abc', domain: 'members-ng.iracing.com', path: '/', expires: -1 }],
|
|
origins: [],
|
|
}),
|
|
validateCookies: vi.fn().mockReturnValue(deps.cookieState),
|
|
getSessionExpiry: vi.fn(),
|
|
write: vi.fn(),
|
|
delete: vi.fn(),
|
|
} as unknown as SessionCookieStore;
|
|
|
|
const mockAuthFlow: IPlaywrightAuthFlow = {
|
|
getLoginUrl: () => 'https://members-ng.iracing.com/login',
|
|
getPostLoginLandingUrl: () => 'https://members-ng.iracing.com/web/racing/hosted/browse-sessions',
|
|
isLoginUrl: (url: string) => url.includes('/login'),
|
|
isAuthenticatedUrl: (url: string) => url.includes('/web/racing/hosted'),
|
|
isLoginSuccessUrl: (url: string) => url.includes('/web/racing/hosted'),
|
|
detectAuthenticatedUi: vi.fn().mockResolvedValue(deps.hasAuthUi),
|
|
detectLoginUi: vi.fn(),
|
|
navigateToAuthenticatedArea: vi.fn(),
|
|
waitForPostLoginRedirect: vi.fn(),
|
|
} as unknown as IPlaywrightAuthFlow;
|
|
|
|
const service = new PlaywrightAuthSessionService(
|
|
mockBrowserSession,
|
|
mockCookieStore,
|
|
mockAuthFlow,
|
|
mockLogger,
|
|
);
|
|
|
|
return { service, mockCookieStore, mockAuthFlow, mockPage };
|
|
}
|
|
|
|
it('treats cookies-valid + login UI as EXPIRED (page wins over cookies)', async () => {
|
|
const { service } = createService({
|
|
pageUrl: 'https://members-ng.iracing.com/web/racing/hosted/browse-sessions',
|
|
hasLoginUi: true,
|
|
hasAuthUi: false,
|
|
cookieState: AuthenticationState.AUTHENTICATED,
|
|
});
|
|
|
|
const result: Result<BrowserAuthenticationState> = await service.verifyPageAuthentication();
|
|
expect(result.isOk()).toBe(true);
|
|
|
|
const browserState = result.unwrap();
|
|
expect(browserState.getCookieValidity()).toBe(true);
|
|
expect(browserState.getPageAuthenticationStatus()).toBe(false);
|
|
expect(browserState.getAuthenticationState()).toBe(AuthenticationState.EXPIRED);
|
|
expect(browserState.requiresReauthentication()).toBe(true);
|
|
});
|
|
|
|
it('treats cookies-valid + authenticated UI without login UI as AUTHENTICATED', async () => {
|
|
const { service } = createService({
|
|
pageUrl: 'https://members-ng.iracing.com/web/racing/hosted/browse-sessions',
|
|
hasLoginUi: false,
|
|
hasAuthUi: true,
|
|
cookieState: AuthenticationState.AUTHENTICATED,
|
|
});
|
|
|
|
const result: Result<BrowserAuthenticationState> = await service.verifyPageAuthentication();
|
|
expect(result.isOk()).toBe(true);
|
|
|
|
const browserState = result.unwrap();
|
|
expect(browserState.getCookieValidity()).toBe(true);
|
|
expect(browserState.getPageAuthenticationStatus()).toBe(true);
|
|
expect(browserState.getAuthenticationState()).toBe(AuthenticationState.AUTHENTICATED);
|
|
expect(browserState.requiresReauthentication()).toBe(false);
|
|
});
|
|
}); |