mirror of
https://github.com/CloakHQ/CloakBrowser.git
synced 2026-06-23 11:41:46 +02:00
refactor: unify timezone parameter naming across Python and JS wrappers
- Rename timezone_id → timezone in launch_context(), launch_persistent_context(), and launch_persistent_context_async() (Python) - Extract _migrate_timezone_id() helper for deprecation compat (DRY) - Always pop timezone_id from kwargs to prevent override via context_kwargs.update() - Use FutureWarning (visible by default) instead of DeprecationWarning - JS: deprecate timezoneId on LaunchContextOptions with runtime shim - Extract migrateTimezoneId<T>() shared helper in playwright.ts (DRY) - Bump version to 0.3.7 in _version.py and package.json - Add 4 Python + 4 JS unit tests for deprecation compat behavior
This commit is contained in:
@@ -6,6 +6,10 @@ Changes are tagged: **[wrapper]** for Python/JS wrapper, **[binary]** for Chromi
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## [0.3.7] — 2026-03-05
|
||||||
|
|
||||||
|
- **[wrapper]** Unify timezone parameter: rename `timezone_id` to `timezone` in `launch_context()`, `launch_persistent_context()`, and `launch_persistent_context_async()` (Python). Old `timezone_id` still works with a deprecation warning. JS: deprecate `timezoneId` on `LaunchContextOptions` — use `timezone` (inherited from `LaunchOptions`)
|
||||||
|
|
||||||
## [0.3.6] — 2026-03-04
|
## [0.3.6] — 2026-03-04
|
||||||
|
|
||||||
- **[wrapper]** `proxy` parameter now accepts a Playwright proxy dict (`{server, bypass, username, password}`) in addition to URL strings — enables bypass lists and separate auth fields (PR #24). **TS note:** type changed from `string` to `string | object` — code that assumed `proxy` is always a string may need a `typeof` narrowing check
|
- **[wrapper]** `proxy` parameter now accepts a Playwright proxy dict (`{server, bypass, username, password}`) in addition to URL strings — enables bypass lists and separate auth fields (PR #24). **TS note:** type changed from `string` to `string | object` — code that assumed `proxy` is always a string may need a `typeof` narrowing check
|
||||||
|
|||||||
@@ -251,7 +251,7 @@ context = launch_context(
|
|||||||
user_agent="Custom UA",
|
user_agent="Custom UA",
|
||||||
viewport={"width": 1920, "height": 1080},
|
viewport={"width": 1920, "height": 1080},
|
||||||
locale="en-US",
|
locale="en-US",
|
||||||
timezone_id="America/New_York",
|
timezone="America/New_York",
|
||||||
)
|
)
|
||||||
page = context.new_page()
|
page = context.new_page()
|
||||||
page.goto("https://protected-site.com")
|
page.goto("https://protected-site.com")
|
||||||
@@ -281,7 +281,7 @@ ctx.close() # profile saved
|
|||||||
ctx = launch_persistent_context("./my-profile", headless=False)
|
ctx = launch_persistent_context("./my-profile", headless=False)
|
||||||
```
|
```
|
||||||
|
|
||||||
Supports all the same options as `launch_context()`: `proxy`, `user_agent`, `viewport`, `locale`, `timezone_id`, `color_scheme`, `geoip`.
|
Supports all the same options as `launch_context()`: `proxy`, `user_agent`, `viewport`, `locale`, `timezone`, `color_scheme`, `geoip`.
|
||||||
|
|
||||||
Async version: `launch_persistent_context_async()`.
|
Async version: `launch_persistent_context_async()`.
|
||||||
|
|
||||||
@@ -327,7 +327,7 @@ const context = await launchContext({
|
|||||||
userAgent: 'Custom UA',
|
userAgent: 'Custom UA',
|
||||||
viewport: { width: 1920, height: 1080 },
|
viewport: { width: 1920, height: 1080 },
|
||||||
locale: 'en-US',
|
locale: 'en-US',
|
||||||
timezoneId: 'America/New_York',
|
timezone: 'America/New_York',
|
||||||
});
|
});
|
||||||
const page = await context.newPage();
|
const page = await context.newPage();
|
||||||
|
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
__version__ = "0.3.6"
|
__version__ = "0.3.7"
|
||||||
|
|||||||
+35
-17
@@ -16,6 +16,7 @@ from __future__ import annotations
|
|||||||
|
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
|
import warnings
|
||||||
from typing import Any, Literal, TypedDict
|
from typing import Any, Literal, TypedDict
|
||||||
from urllib.parse import unquote, urlparse, urlunparse
|
from urllib.parse import unquote, urlparse, urlunparse
|
||||||
|
|
||||||
@@ -25,6 +26,17 @@ from .download import ensure_binary
|
|||||||
logger = logging.getLogger("cloakbrowser")
|
logger = logging.getLogger("cloakbrowser")
|
||||||
|
|
||||||
|
|
||||||
|
def _migrate_timezone_id(timezone: str | None, kwargs: dict[str, Any]) -> str | None:
|
||||||
|
"""Pop deprecated timezone_id from kwargs, warn, return resolved timezone."""
|
||||||
|
if "timezone_id" in kwargs:
|
||||||
|
warnings.warn("timezone_id is deprecated, use timezone instead", FutureWarning, stacklevel=3)
|
||||||
|
if timezone is None:
|
||||||
|
timezone = kwargs.pop("timezone_id")
|
||||||
|
else:
|
||||||
|
kwargs.pop("timezone_id")
|
||||||
|
return timezone
|
||||||
|
|
||||||
|
|
||||||
class _ProxySettingsRequired(TypedDict):
|
class _ProxySettingsRequired(TypedDict):
|
||||||
server: str
|
server: str
|
||||||
|
|
||||||
@@ -184,7 +196,7 @@ def launch_persistent_context(
|
|||||||
user_agent: str | None = None,
|
user_agent: str | None = None,
|
||||||
viewport: dict | None = None,
|
viewport: dict | None = None,
|
||||||
locale: str | None = None,
|
locale: str | None = None,
|
||||||
timezone_id: str | None = None,
|
timezone: str | None = None,
|
||||||
color_scheme: Literal["light", "dark", "no-preference"] | None = None,
|
color_scheme: Literal["light", "dark", "no-preference"] | None = None,
|
||||||
geoip: bool = False,
|
geoip: bool = False,
|
||||||
**kwargs: Any,
|
**kwargs: Any,
|
||||||
@@ -206,7 +218,7 @@ def launch_persistent_context(
|
|||||||
user_agent: Custom user agent string.
|
user_agent: Custom user agent string.
|
||||||
viewport: Viewport size dict, e.g. {"width": 1920, "height": 1080}.
|
viewport: Viewport size dict, e.g. {"width": 1920, "height": 1080}.
|
||||||
locale: Browser locale, e.g. "en-US".
|
locale: Browser locale, e.g. "en-US".
|
||||||
timezone_id: Timezone, e.g. "America/New_York".
|
timezone: IANA timezone (e.g. 'America/New_York').
|
||||||
color_scheme: Color scheme preference — 'light', 'dark', or 'no-preference'.
|
color_scheme: Color scheme preference — 'light', 'dark', or 'no-preference'.
|
||||||
Default: None (uses Chromium default, which is 'light').
|
Default: None (uses Chromium default, which is 'light').
|
||||||
geoip: Auto-detect timezone/locale from proxy IP (default False).
|
geoip: Auto-detect timezone/locale from proxy IP (default False).
|
||||||
@@ -226,9 +238,11 @@ def launch_persistent_context(
|
|||||||
"""
|
"""
|
||||||
from patchright.sync_api import sync_playwright
|
from patchright.sync_api import sync_playwright
|
||||||
|
|
||||||
|
timezone = _migrate_timezone_id(timezone, kwargs)
|
||||||
|
|
||||||
binary_path = ensure_binary()
|
binary_path = ensure_binary()
|
||||||
timezone_id, locale = _maybe_resolve_geoip(geoip, proxy, timezone_id, locale)
|
timezone, locale = _maybe_resolve_geoip(geoip, proxy, timezone, locale)
|
||||||
chrome_args = _build_args(stealth_args, args, timezone=timezone_id, locale=locale)
|
chrome_args = _build_args(stealth_args, args, timezone=timezone, locale=locale)
|
||||||
|
|
||||||
logger.debug(
|
logger.debug(
|
||||||
"Launching persistent stealth Chromium (headless=%s, user_data_dir=%s)",
|
"Launching persistent stealth Chromium (headless=%s, user_data_dir=%s)",
|
||||||
@@ -242,8 +256,8 @@ def launch_persistent_context(
|
|||||||
context_kwargs["viewport"] = viewport or DEFAULT_VIEWPORT
|
context_kwargs["viewport"] = viewport or DEFAULT_VIEWPORT
|
||||||
if locale:
|
if locale:
|
||||||
context_kwargs["locale"] = locale
|
context_kwargs["locale"] = locale
|
||||||
if timezone_id:
|
if timezone:
|
||||||
context_kwargs["timezone_id"] = timezone_id
|
context_kwargs["timezone_id"] = timezone
|
||||||
if color_scheme:
|
if color_scheme:
|
||||||
context_kwargs["color_scheme"] = color_scheme
|
context_kwargs["color_scheme"] = color_scheme
|
||||||
context_kwargs.update(kwargs)
|
context_kwargs.update(kwargs)
|
||||||
@@ -280,7 +294,7 @@ async def launch_persistent_context_async(
|
|||||||
user_agent: str | None = None,
|
user_agent: str | None = None,
|
||||||
viewport: dict | None = None,
|
viewport: dict | None = None,
|
||||||
locale: str | None = None,
|
locale: str | None = None,
|
||||||
timezone_id: str | None = None,
|
timezone: str | None = None,
|
||||||
color_scheme: Literal["light", "dark", "no-preference"] | None = None,
|
color_scheme: Literal["light", "dark", "no-preference"] | None = None,
|
||||||
geoip: bool = False,
|
geoip: bool = False,
|
||||||
**kwargs: Any,
|
**kwargs: Any,
|
||||||
@@ -301,7 +315,7 @@ async def launch_persistent_context_async(
|
|||||||
user_agent: Custom user agent string.
|
user_agent: Custom user agent string.
|
||||||
viewport: Viewport size dict, e.g. {"width": 1920, "height": 1080}.
|
viewport: Viewport size dict, e.g. {"width": 1920, "height": 1080}.
|
||||||
locale: Browser locale, e.g. "en-US".
|
locale: Browser locale, e.g. "en-US".
|
||||||
timezone_id: Timezone, e.g. "America/New_York".
|
timezone: IANA timezone (e.g. 'America/New_York').
|
||||||
color_scheme: Color scheme preference — 'light', 'dark', or 'no-preference'.
|
color_scheme: Color scheme preference — 'light', 'dark', or 'no-preference'.
|
||||||
geoip: Auto-detect timezone/locale from proxy IP (default False).
|
geoip: Auto-detect timezone/locale from proxy IP (default False).
|
||||||
**kwargs: Passed directly to playwright.chromium.launch_persistent_context().
|
**kwargs: Passed directly to playwright.chromium.launch_persistent_context().
|
||||||
@@ -324,9 +338,11 @@ async def launch_persistent_context_async(
|
|||||||
"""
|
"""
|
||||||
from patchright.async_api import async_playwright
|
from patchright.async_api import async_playwright
|
||||||
|
|
||||||
|
timezone = _migrate_timezone_id(timezone, kwargs)
|
||||||
|
|
||||||
binary_path = ensure_binary()
|
binary_path = ensure_binary()
|
||||||
timezone_id, locale = _maybe_resolve_geoip(geoip, proxy, timezone_id, locale)
|
timezone, locale = _maybe_resolve_geoip(geoip, proxy, timezone, locale)
|
||||||
chrome_args = _build_args(stealth_args, args, timezone=timezone_id, locale=locale)
|
chrome_args = _build_args(stealth_args, args, timezone=timezone, locale=locale)
|
||||||
|
|
||||||
logger.debug(
|
logger.debug(
|
||||||
"Launching persistent stealth Chromium async (headless=%s, user_data_dir=%s)",
|
"Launching persistent stealth Chromium async (headless=%s, user_data_dir=%s)",
|
||||||
@@ -340,8 +356,8 @@ async def launch_persistent_context_async(
|
|||||||
context_kwargs["viewport"] = viewport or DEFAULT_VIEWPORT
|
context_kwargs["viewport"] = viewport or DEFAULT_VIEWPORT
|
||||||
if locale:
|
if locale:
|
||||||
context_kwargs["locale"] = locale
|
context_kwargs["locale"] = locale
|
||||||
if timezone_id:
|
if timezone:
|
||||||
context_kwargs["timezone_id"] = timezone_id
|
context_kwargs["timezone_id"] = timezone
|
||||||
if color_scheme:
|
if color_scheme:
|
||||||
context_kwargs["color_scheme"] = color_scheme
|
context_kwargs["color_scheme"] = color_scheme
|
||||||
context_kwargs.update(kwargs)
|
context_kwargs.update(kwargs)
|
||||||
@@ -377,7 +393,7 @@ def launch_context(
|
|||||||
user_agent: str | None = None,
|
user_agent: str | None = None,
|
||||||
viewport: dict | None = None,
|
viewport: dict | None = None,
|
||||||
locale: str | None = None,
|
locale: str | None = None,
|
||||||
timezone_id: str | None = None,
|
timezone: str | None = None,
|
||||||
color_scheme: Literal["light", "dark", "no-preference"] | None = None,
|
color_scheme: Literal["light", "dark", "no-preference"] | None = None,
|
||||||
geoip: bool = False,
|
geoip: bool = False,
|
||||||
**kwargs: Any,
|
**kwargs: Any,
|
||||||
@@ -395,7 +411,7 @@ def launch_context(
|
|||||||
user_agent: Custom user agent string.
|
user_agent: Custom user agent string.
|
||||||
viewport: Viewport size dict, e.g. {"width": 1920, "height": 1080}.
|
viewport: Viewport size dict, e.g. {"width": 1920, "height": 1080}.
|
||||||
locale: Browser locale, e.g. "en-US".
|
locale: Browser locale, e.g. "en-US".
|
||||||
timezone_id: Timezone, e.g. "America/New_York".
|
timezone: IANA timezone (e.g. 'America/New_York').
|
||||||
color_scheme: Color scheme preference — 'light', 'dark', or 'no-preference'.
|
color_scheme: Color scheme preference — 'light', 'dark', or 'no-preference'.
|
||||||
Default: None (uses Chromium default, which is 'light').
|
Default: None (uses Chromium default, which is 'light').
|
||||||
Note: 'no-preference' doesn't work in Patchright (falls back to 'light').
|
Note: 'no-preference' doesn't work in Patchright (falls back to 'light').
|
||||||
@@ -405,9 +421,11 @@ def launch_context(
|
|||||||
Returns:
|
Returns:
|
||||||
Playwright BrowserContext object.
|
Playwright BrowserContext object.
|
||||||
"""
|
"""
|
||||||
|
timezone = _migrate_timezone_id(timezone, kwargs)
|
||||||
|
|
||||||
# Resolve geoip BEFORE launch() to avoid double-resolution and ensure
|
# Resolve geoip BEFORE launch() to avoid double-resolution and ensure
|
||||||
# resolved values flow to both binary flags AND context params
|
# resolved values flow to both binary flags AND context params
|
||||||
timezone_id, locale = _maybe_resolve_geoip(geoip, proxy, timezone_id, locale)
|
timezone, locale = _maybe_resolve_geoip(geoip, proxy, timezone, locale)
|
||||||
# Skip --fingerprint-timezone binary flag: it only applies to the default
|
# Skip --fingerprint-timezone binary flag: it only applies to the default
|
||||||
# context and interferes with Playwright's timezone_id on new contexts.
|
# context and interferes with Playwright's timezone_id on new contexts.
|
||||||
# Timezone is set via browser.new_context(timezone_id=...) below instead.
|
# Timezone is set via browser.new_context(timezone_id=...) below instead.
|
||||||
@@ -420,8 +438,8 @@ def launch_context(
|
|||||||
context_kwargs["viewport"] = viewport or DEFAULT_VIEWPORT
|
context_kwargs["viewport"] = viewport or DEFAULT_VIEWPORT
|
||||||
if locale:
|
if locale:
|
||||||
context_kwargs["locale"] = locale
|
context_kwargs["locale"] = locale
|
||||||
if timezone_id:
|
if timezone:
|
||||||
context_kwargs["timezone_id"] = timezone_id
|
context_kwargs["timezone_id"] = timezone
|
||||||
if color_scheme:
|
if color_scheme:
|
||||||
context_kwargs["color_scheme"] = color_scheme
|
context_kwargs["color_scheme"] = color_scheme
|
||||||
context_kwargs.update(kwargs)
|
context_kwargs.update(kwargs)
|
||||||
|
|||||||
+1
-1
@@ -97,7 +97,7 @@ const context = await launchContext({
|
|||||||
userAgent: 'Custom UA',
|
userAgent: 'Custom UA',
|
||||||
viewport: { width: 1920, height: 1080 },
|
viewport: { width: 1920, height: 1080 },
|
||||||
locale: 'en-US',
|
locale: 'en-US',
|
||||||
timezoneId: 'America/New_York',
|
timezone: 'America/New_York',
|
||||||
});
|
});
|
||||||
|
|
||||||
// Persistent profile — stay logged in, bypass incognito detection, load extensions
|
// Persistent profile — stay logged in, bypass incognito detection, load extensions
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "cloakbrowser",
|
"name": "cloakbrowser",
|
||||||
"version": "0.3.6",
|
"version": "0.3.7",
|
||||||
"description": "Stealth Chromium that passes every bot detection test. Drop-in Playwright/Puppeteer replacement with source-level fingerprint patches.",
|
"description": "Stealth Chromium that passes every bot detection test. Drop-in Playwright/Puppeteer replacement with source-level fingerprint patches.",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
|
|||||||
@@ -9,6 +9,17 @@ import { DEFAULT_VIEWPORT, getDefaultStealthArgs } from "./config.js";
|
|||||||
import { ensureBinary } from "./download.js";
|
import { ensureBinary } from "./download.js";
|
||||||
import { parseProxyUrl } from "./proxy.js";
|
import { parseProxyUrl } from "./proxy.js";
|
||||||
|
|
||||||
|
/** @internal Migrate deprecated timezoneId → timezone, warn once. Exported for testing. */
|
||||||
|
export function migrateTimezoneId<T extends { timezone?: string; timezoneId?: string }>(options: T): T {
|
||||||
|
if (options.timezoneId != null) {
|
||||||
|
console.warn("[cloakbrowser] timezoneId is deprecated, use timezone instead");
|
||||||
|
const merged = { ...options, timezone: options.timezone ?? options.timezoneId };
|
||||||
|
delete (merged as any).timezoneId;
|
||||||
|
return merged;
|
||||||
|
}
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Launch stealth Chromium browser via Playwright.
|
* Launch stealth Chromium browser via Playwright.
|
||||||
*
|
*
|
||||||
@@ -62,6 +73,7 @@ export async function launch(options: LaunchOptions = {}): Promise<Browser> {
|
|||||||
export async function launchContext(
|
export async function launchContext(
|
||||||
options: LaunchContextOptions = {}
|
options: LaunchContextOptions = {}
|
||||||
): Promise<BrowserContext> {
|
): Promise<BrowserContext> {
|
||||||
|
options = migrateTimezoneId(options);
|
||||||
// Resolve geoip BEFORE launch() to avoid double-resolution
|
// Resolve geoip BEFORE launch() to avoid double-resolution
|
||||||
const resolved = await maybeResolveGeoip(options);
|
const resolved = await maybeResolveGeoip(options);
|
||||||
// Skip --fingerprint-timezone binary flag: it only applies to the default
|
// Skip --fingerprint-timezone binary flag: it only applies to the default
|
||||||
@@ -117,6 +129,7 @@ export async function launchContext(
|
|||||||
export async function launchPersistentContext(
|
export async function launchPersistentContext(
|
||||||
options: LaunchPersistentContextOptions
|
options: LaunchPersistentContextOptions
|
||||||
): Promise<BrowserContext> {
|
): Promise<BrowserContext> {
|
||||||
|
options = migrateTimezoneId(options);
|
||||||
const { chromium } = await import("playwright-core");
|
const { chromium } = await import("playwright-core");
|
||||||
|
|
||||||
const binaryPath = process.env.CLOAKBROWSER_BINARY_PATH || (await ensureBinary());
|
const binaryPath = process.env.CLOAKBROWSER_BINARY_PATH || (await ensureBinary());
|
||||||
|
|||||||
+1
-1
@@ -33,7 +33,7 @@ export interface LaunchContextOptions extends LaunchOptions {
|
|||||||
viewport?: { width: number; height: number };
|
viewport?: { width: number; height: number };
|
||||||
/** Browser locale, e.g. "en-US". */
|
/** Browser locale, e.g. "en-US". */
|
||||||
locale?: string;
|
locale?: string;
|
||||||
/** Timezone, e.g. "America/New_York". */
|
/** @deprecated Use `timezone` (inherited from LaunchOptions) instead. */
|
||||||
timezoneId?: string;
|
timezoneId?: string;
|
||||||
/** Color scheme preference — 'light', 'dark', or 'no-preference'. */
|
/** Color scheme preference — 'light', 'dark', or 'no-preference'. */
|
||||||
colorScheme?: "light" | "dark" | "no-preference";
|
colorScheme?: "light" | "dark" | "no-preference";
|
||||||
|
|||||||
+28
-1
@@ -7,7 +7,7 @@ import {
|
|||||||
getBinaryDir,
|
getBinaryDir,
|
||||||
getDownloadUrl,
|
getDownloadUrl,
|
||||||
} from "../src/config.js";
|
} from "../src/config.js";
|
||||||
import { _buildArgsForTest } from "../src/playwright.js";
|
import { _buildArgsForTest, migrateTimezoneId } from "../src/playwright.js";
|
||||||
|
|
||||||
describe("config", () => {
|
describe("config", () => {
|
||||||
it("CHROMIUM_VERSION matches expected format", () => {
|
it("CHROMIUM_VERSION matches expected format", () => {
|
||||||
@@ -98,3 +98,30 @@ describe("buildArgs timezone/locale", () => {
|
|||||||
expect(args.some(a => a.startsWith("--lang="))).toBe(false);
|
expect(args.some(a => a.startsWith("--lang="))).toBe(false);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("migrateTimezoneId deprecation", () => {
|
||||||
|
it("migrates timezoneId to timezone", () => {
|
||||||
|
const result = migrateTimezoneId({ timezoneId: "Europe/Paris" });
|
||||||
|
expect(result.timezone).toBe("Europe/Paris");
|
||||||
|
expect(result).not.toHaveProperty("timezoneId");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("preserves explicit timezone over timezoneId", () => {
|
||||||
|
const result = migrateTimezoneId({ timezone: "UTC", timezoneId: "Europe/Paris" });
|
||||||
|
expect(result.timezone).toBe("UTC");
|
||||||
|
expect(result).not.toHaveProperty("timezoneId");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("returns options unchanged when no timezoneId", () => {
|
||||||
|
const opts = { timezone: "UTC" };
|
||||||
|
const result = migrateTimezoneId(opts);
|
||||||
|
expect(result).toBe(opts); // same reference, no copy
|
||||||
|
expect(result.timezone).toBe("UTC");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("returns options unchanged when neither is set", () => {
|
||||||
|
const opts = {};
|
||||||
|
const result = migrateTimezoneId(opts);
|
||||||
|
expect(result).toBe(opts);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
"""Unit tests for _build_args timezone/locale injection."""
|
"""Unit tests for _build_args timezone/locale injection and deprecation compat."""
|
||||||
|
|
||||||
from cloakbrowser.browser import _build_args
|
import warnings
|
||||||
|
|
||||||
|
from cloakbrowser.browser import _build_args, _migrate_timezone_id
|
||||||
|
|
||||||
|
|
||||||
def test_timezone_injected():
|
def test_timezone_injected():
|
||||||
@@ -44,3 +46,49 @@ def test_extra_args_preserved():
|
|||||||
assert "--disable-gpu" in args
|
assert "--disable-gpu" in args
|
||||||
assert "--fingerprint-timezone=Asia/Tokyo" in args
|
assert "--fingerprint-timezone=Asia/Tokyo" in args
|
||||||
assert "--lang=ja-JP" in args
|
assert "--lang=ja-JP" in args
|
||||||
|
|
||||||
|
|
||||||
|
# --- _migrate_timezone_id deprecation compat ---
|
||||||
|
|
||||||
|
|
||||||
|
def test_migrate_old_param_only():
|
||||||
|
"""timezone_id in kwargs should be promoted to timezone."""
|
||||||
|
kwargs = {"timezone_id": "Europe/Paris"}
|
||||||
|
with warnings.catch_warnings(record=True) as w:
|
||||||
|
warnings.simplefilter("always")
|
||||||
|
result = _migrate_timezone_id(None, kwargs)
|
||||||
|
assert result == "Europe/Paris"
|
||||||
|
assert "timezone_id" not in kwargs
|
||||||
|
assert len(w) == 1 and issubclass(w[0].category, FutureWarning)
|
||||||
|
|
||||||
|
|
||||||
|
def test_migrate_new_param_wins():
|
||||||
|
"""Explicit timezone takes precedence; timezone_id is still popped."""
|
||||||
|
kwargs = {"timezone_id": "Europe/Paris"}
|
||||||
|
with warnings.catch_warnings(record=True) as w:
|
||||||
|
warnings.simplefilter("always")
|
||||||
|
result = _migrate_timezone_id("UTC", kwargs)
|
||||||
|
assert result == "UTC"
|
||||||
|
assert "timezone_id" not in kwargs
|
||||||
|
assert len(w) == 1
|
||||||
|
|
||||||
|
|
||||||
|
def test_migrate_no_old_param():
|
||||||
|
"""No warning when timezone_id is absent."""
|
||||||
|
kwargs = {"other": "value"}
|
||||||
|
with warnings.catch_warnings(record=True) as w:
|
||||||
|
warnings.simplefilter("always")
|
||||||
|
result = _migrate_timezone_id("UTC", kwargs)
|
||||||
|
assert result == "UTC"
|
||||||
|
assert "other" in kwargs
|
||||||
|
assert len(w) == 0
|
||||||
|
|
||||||
|
|
||||||
|
def test_migrate_both_none():
|
||||||
|
"""Neither param set — returns None, no warning."""
|
||||||
|
kwargs = {}
|
||||||
|
with warnings.catch_warnings(record=True) as w:
|
||||||
|
warnings.simplefilter("always")
|
||||||
|
result = _migrate_timezone_id(None, kwargs)
|
||||||
|
assert result is None
|
||||||
|
assert len(w) == 0
|
||||||
|
|||||||
Reference in New Issue
Block a user