Add comprehensive tests and docs for darkMode & hideSelectors
Some checks failed
Build & Deploy to Staging / Build & Deploy to Staging (push) Has been cancelled
Some checks failed
Build & Deploy to Staging / Build & Deploy to Staging (push) Has been cancelled
- Add 5 new Python tests for darkMode and hideSelectors parameters - Update Node.js SDK README with darkMode/hideSelectors examples - Update Python SDK README with darkMode/hideSelectors examples - Add API reference entries for new parameters - All tests passing: Node.js (19 tests), Python (22 tests) Features already implemented in v0.7.0 but needed better test coverage and documentation.
This commit is contained in:
parent
28f4a93dc3
commit
e6c34ef760
3 changed files with 214 additions and 0 deletions
|
|
@ -72,6 +72,51 @@ const screenshot = await snap.capture({
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Dark Mode Capture
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Capture in dark mode (prefers-color-scheme: dark)
|
||||||
|
const darkScreenshot = await snap.capture({
|
||||||
|
url: 'https://example.com',
|
||||||
|
darkMode: true,
|
||||||
|
format: 'png',
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### Hide Elements Before Capture
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Hide cookie banners, popups, ads
|
||||||
|
const cleanScreenshot = await snap.capture({
|
||||||
|
url: 'https://example.com',
|
||||||
|
hideSelectors: [
|
||||||
|
'.cookie-banner',
|
||||||
|
'.popup-overlay',
|
||||||
|
'#advertisement',
|
||||||
|
'.tracking-notice'
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
// Hide single element
|
||||||
|
const singleHide = await snap.capture('https://example.com', {
|
||||||
|
hideSelectors: '.newsletter-popup',
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### Combined Dark Mode + Element Hiding
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Perfect for clean marketing screenshots
|
||||||
|
const marketingShot = await snap.capture({
|
||||||
|
url: 'https://your-saas-app.com',
|
||||||
|
darkMode: true,
|
||||||
|
hideSelectors: ['.dev-banner', '.beta-notice'],
|
||||||
|
width: 1920,
|
||||||
|
height: 1080,
|
||||||
|
deviceScale: 2,
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
## API Reference
|
## API Reference
|
||||||
|
|
||||||
### `new SnapAPI(apiKey, config?)`
|
### `new SnapAPI(apiKey, config?)`
|
||||||
|
|
@ -98,6 +143,8 @@ Returns a `Promise<Buffer>` containing the screenshot image.
|
||||||
| `deviceScale` | `number` | `1` | Device pixel ratio (1–3) |
|
| `deviceScale` | `number` | `1` | Device pixel ratio (1–3) |
|
||||||
| `delay` | `number` | `0` | Extra delay in ms (0–5000) |
|
| `delay` | `number` | `0` | Extra delay in ms (0–5000) |
|
||||||
| `waitUntil` | `string` | `'domcontentloaded'` | Load event to wait for |
|
| `waitUntil` | `string` | `'domcontentloaded'` | Load event to wait for |
|
||||||
|
| `darkMode` | `boolean` | `false` | Emulate prefers-color-scheme: dark |
|
||||||
|
| `hideSelectors` | `string \| string[]` | — | CSS selectors to hide before capture |
|
||||||
|
|
||||||
### `snap.health()`
|
### `snap.health()`
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -75,6 +75,52 @@ screenshot = snap.capture(
|
||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Dark Mode Capture
|
||||||
|
|
||||||
|
```python
|
||||||
|
# Capture in dark mode (prefers-color-scheme: dark)
|
||||||
|
dark_screenshot = snap.capture(
|
||||||
|
"https://example.com",
|
||||||
|
dark_mode=True,
|
||||||
|
format="png",
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Hide Elements Before Capture
|
||||||
|
|
||||||
|
```python
|
||||||
|
# Hide cookie banners, popups, ads
|
||||||
|
clean_screenshot = snap.capture(
|
||||||
|
"https://example.com",
|
||||||
|
hide_selectors=[
|
||||||
|
".cookie-banner",
|
||||||
|
".popup-overlay",
|
||||||
|
"#advertisement",
|
||||||
|
".tracking-notice"
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
# Hide single element
|
||||||
|
single_hide = snap.capture(
|
||||||
|
"https://example.com",
|
||||||
|
hide_selectors=".newsletter-popup",
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Combined Dark Mode + Element Hiding
|
||||||
|
|
||||||
|
```python
|
||||||
|
# Perfect for clean marketing screenshots
|
||||||
|
marketing_shot = snap.capture(
|
||||||
|
"https://your-saas-app.com",
|
||||||
|
dark_mode=True,
|
||||||
|
hide_selectors=[".dev-banner", ".beta-notice"],
|
||||||
|
width=1920,
|
||||||
|
height=1080,
|
||||||
|
device_scale=2,
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
### Error Handling
|
### Error Handling
|
||||||
|
|
||||||
```python
|
```python
|
||||||
|
|
@ -106,6 +152,8 @@ except SnapAPIError as e:
|
||||||
| `device_scale` | `float` | `1` | Device pixel ratio (1–3) |
|
| `device_scale` | `float` | `1` | Device pixel ratio (1–3) |
|
||||||
| `delay` | `int` | `0` | Extra delay in ms (0–5000) |
|
| `delay` | `int` | `0` | Extra delay in ms (0–5000) |
|
||||||
| `wait_until` | `str` | `"domcontentloaded"` | Load event |
|
| `wait_until` | `str` | `"domcontentloaded"` | Load event |
|
||||||
|
| `dark_mode` | `bool` | `False` | Emulate prefers-color-scheme: dark |
|
||||||
|
| `hide_selectors` | `list` | — | CSS selectors to hide before capture |
|
||||||
|
|
||||||
### `snap.health() -> dict`
|
### `snap.health() -> dict`
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -155,6 +155,91 @@ class TestSnapAPI(unittest.TestCase):
|
||||||
self.assertEqual(request_body, expected_body)
|
self.assertEqual(request_body, expected_body)
|
||||||
self.assertEqual(result, b'fake-image-data')
|
self.assertEqual(result, b'fake-image-data')
|
||||||
|
|
||||||
|
@patch('snapapi.client.urllib.request.urlopen')
|
||||||
|
def test_capture_with_dark_mode_parameter(self, mock_urlopen):
|
||||||
|
"""capture with dark_mode parameter should work correctly."""
|
||||||
|
# Mock response
|
||||||
|
mock_response = Mock()
|
||||||
|
mock_response.read.return_value = b'fake-dark-image-data'
|
||||||
|
mock_response.__enter__ = Mock(return_value=mock_response)
|
||||||
|
mock_response.__exit__ = Mock(return_value=None)
|
||||||
|
mock_urlopen.return_value = mock_response
|
||||||
|
|
||||||
|
result = self.snap.capture(
|
||||||
|
url="https://example.com",
|
||||||
|
dark_mode=True
|
||||||
|
)
|
||||||
|
|
||||||
|
# Verify request body contains darkMode
|
||||||
|
request_arg = mock_urlopen.call_args[0][0]
|
||||||
|
request_body = json.loads(request_arg.data.decode())
|
||||||
|
|
||||||
|
expected_body = {
|
||||||
|
"url": "https://example.com",
|
||||||
|
"darkMode": True
|
||||||
|
}
|
||||||
|
|
||||||
|
self.assertEqual(request_body, expected_body)
|
||||||
|
self.assertEqual(result, b'fake-dark-image-data')
|
||||||
|
|
||||||
|
@patch('snapapi.client.urllib.request.urlopen')
|
||||||
|
def test_capture_with_hide_selectors_list_parameter(self, mock_urlopen):
|
||||||
|
"""capture with hide_selectors as list should work correctly."""
|
||||||
|
# Mock response
|
||||||
|
mock_response = Mock()
|
||||||
|
mock_response.read.return_value = b'fake-clean-image-data'
|
||||||
|
mock_response.__enter__ = Mock(return_value=mock_response)
|
||||||
|
mock_response.__exit__ = Mock(return_value=None)
|
||||||
|
mock_urlopen.return_value = mock_response
|
||||||
|
|
||||||
|
result = self.snap.capture(
|
||||||
|
url="https://example.com",
|
||||||
|
hide_selectors=['.ads', '.popup', '#cookie-banner']
|
||||||
|
)
|
||||||
|
|
||||||
|
# Verify request body contains hideSelectors
|
||||||
|
request_arg = mock_urlopen.call_args[0][0]
|
||||||
|
request_body = json.loads(request_arg.data.decode())
|
||||||
|
|
||||||
|
expected_body = {
|
||||||
|
"url": "https://example.com",
|
||||||
|
"hideSelectors": ['.ads', '.popup', '#cookie-banner']
|
||||||
|
}
|
||||||
|
|
||||||
|
self.assertEqual(request_body, expected_body)
|
||||||
|
self.assertEqual(result, b'fake-clean-image-data')
|
||||||
|
|
||||||
|
@patch('snapapi.client.urllib.request.urlopen')
|
||||||
|
def test_capture_with_both_dark_mode_and_hide_selectors(self, mock_urlopen):
|
||||||
|
"""capture with both dark_mode and hide_selectors should work correctly."""
|
||||||
|
# Mock response
|
||||||
|
mock_response = Mock()
|
||||||
|
mock_response.read.return_value = b'fake-dark-clean-image-data'
|
||||||
|
mock_response.__enter__ = Mock(return_value=mock_response)
|
||||||
|
mock_response.__exit__ = Mock(return_value=None)
|
||||||
|
mock_urlopen.return_value = mock_response
|
||||||
|
|
||||||
|
result = self.snap.capture(
|
||||||
|
url="https://example.com",
|
||||||
|
dark_mode=True,
|
||||||
|
hide_selectors=['.tracking', '.ads'],
|
||||||
|
format="png"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Verify request body contains both parameters
|
||||||
|
request_arg = mock_urlopen.call_args[0][0]
|
||||||
|
request_body = json.loads(request_arg.data.decode())
|
||||||
|
|
||||||
|
expected_body = {
|
||||||
|
"url": "https://example.com",
|
||||||
|
"darkMode": True,
|
||||||
|
"hideSelectors": ['.tracking', '.ads'],
|
||||||
|
"format": "png"
|
||||||
|
}
|
||||||
|
|
||||||
|
self.assertEqual(request_body, expected_body)
|
||||||
|
self.assertEqual(result, b'fake-dark-clean-image-data')
|
||||||
|
|
||||||
def test_capture_raises_value_error_if_no_url(self):
|
def test_capture_raises_value_error_if_no_url(self):
|
||||||
"""capture() should raise ValueError if no url provided."""
|
"""capture() should raise ValueError if no url provided."""
|
||||||
with self.assertRaises(ValueError) as cm:
|
with self.assertRaises(ValueError) as cm:
|
||||||
|
|
@ -364,6 +449,40 @@ class TestScreenshotOptions(unittest.TestCase):
|
||||||
expected = {"url": "https://example.com"}
|
expected = {"url": "https://example.com"}
|
||||||
self.assertEqual(result, expected)
|
self.assertEqual(result, expected)
|
||||||
|
|
||||||
|
def test_to_dict_with_dark_mode_and_hide_selectors(self):
|
||||||
|
"""to_dict() should correctly handle darkMode and hideSelectors."""
|
||||||
|
options = ScreenshotOptions(
|
||||||
|
url="https://example.com",
|
||||||
|
dark_mode=True,
|
||||||
|
hide_selectors=['.ads', '.popup', '#banner']
|
||||||
|
)
|
||||||
|
|
||||||
|
result = options.to_dict()
|
||||||
|
|
||||||
|
expected = {
|
||||||
|
"url": "https://example.com",
|
||||||
|
"darkMode": True, # snake_case -> camelCase
|
||||||
|
"hideSelectors": ['.ads', '.popup', '#banner'] # snake_case -> camelCase
|
||||||
|
}
|
||||||
|
|
||||||
|
self.assertEqual(result, expected)
|
||||||
|
|
||||||
|
def test_to_dict_with_dark_mode_false(self):
|
||||||
|
"""to_dict() should include darkMode when explicitly set to False."""
|
||||||
|
options = ScreenshotOptions(
|
||||||
|
url="https://example.com",
|
||||||
|
dark_mode=False
|
||||||
|
)
|
||||||
|
|
||||||
|
result = options.to_dict()
|
||||||
|
|
||||||
|
expected = {
|
||||||
|
"url": "https://example.com",
|
||||||
|
"darkMode": False
|
||||||
|
}
|
||||||
|
|
||||||
|
self.assertEqual(result, expected)
|
||||||
|
|
||||||
|
|
||||||
class TestSnapAPIError(unittest.TestCase):
|
class TestSnapAPIError(unittest.TestCase):
|
||||||
"""Test cases for SnapAPIError exception."""
|
"""Test cases for SnapAPIError exception."""
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue