mirror of
https://github.com/runablehq/mini-browser.git
synced 2026-09-20 13:45:46 +08:00
Merge pull request #4 from runablehq/shashwat-viewportScreenshot
chore: viewport option for screenshot
This commit is contained in:
@@ -68,6 +68,7 @@ Navigation:
|
||||
Observe:
|
||||
text [selector] Visible text (selector uses querySelector, default: body)
|
||||
shot [file] Screenshot (default: ./shot.png)
|
||||
--width/--height temporarily resize viewport for the shot
|
||||
snap Interactive elements via Accessibility Tree
|
||||
|
||||
Interact:
|
||||
@@ -99,6 +100,8 @@ Flags:
|
||||
--json structured output (snap, tab list, logs, audit)
|
||||
--right right-click
|
||||
--double double-click
|
||||
--width <px> screenshot viewport width
|
||||
--height <px> screenshot viewport height
|
||||
--fps <n> recording frame rate (default: 30)
|
||||
--scale <n> recording scale factor (default: 1)
|
||||
```
|
||||
@@ -115,6 +118,9 @@ command runs. For heavy SPAs that fetch data after mount, follow up with
|
||||
|
||||
### Observation
|
||||
|
||||
`shot --width <px> --height <px>` temporarily resizes the viewport to the
|
||||
given dimensions for the screenshot, then restores the original viewport.
|
||||
|
||||
`text` calls `querySelector` — returns first match only. `text "p"` may return
|
||||
empty if the first `<p>` on the page is empty. Use a scoped selector like
|
||||
`text "main"` or `text "#content"` for better results on noisy pages.
|
||||
|
||||
@@ -154,6 +154,7 @@ mb wait url:/dashboard
|
||||
|
||||
```bash
|
||||
mb shot page.png
|
||||
mb shot page.png --width 1440 --height 900
|
||||
```
|
||||
|
||||
### Extract text
|
||||
|
||||
+31
-3
@@ -1,10 +1,38 @@
|
||||
import { connect } from "../lib/browser"
|
||||
import type { Flags } from "../lib/flags"
|
||||
|
||||
interface ViewportFlagsInput {
|
||||
flags: Flags
|
||||
}
|
||||
|
||||
const getViewportSize = ({ flags }: ViewportFlagsInput) => {
|
||||
const { width, height } = flags
|
||||
const hasWidth = width !== undefined
|
||||
const hasHeight = height !== undefined
|
||||
|
||||
if (!hasWidth && !hasHeight) return undefined
|
||||
if (!hasWidth || !hasHeight) {
|
||||
throw new Error("--width and --height must be provided together.")
|
||||
}
|
||||
|
||||
return { width: width!, height: height! }
|
||||
}
|
||||
|
||||
export const shot = async (args: string[], flags: Flags) => {
|
||||
const path = args[0] || "./shot.png"
|
||||
const viewportSize = getViewportSize({ flags })
|
||||
const { page, close } = await connect(flags.tab)
|
||||
await page.screenshot({ path, type: "png" })
|
||||
console.log(path)
|
||||
await close()
|
||||
const originalViewport = page.viewport()
|
||||
try {
|
||||
if (viewportSize) {
|
||||
await page.setViewport(viewportSize)
|
||||
}
|
||||
await page.screenshot({ path, type: "png" })
|
||||
console.log(path)
|
||||
} finally {
|
||||
if (viewportSize && originalViewport) {
|
||||
await page.setViewport(originalViewport)
|
||||
}
|
||||
await close()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@ Navigation:
|
||||
|
||||
Observe:
|
||||
shot [file] Screenshot (default: ./shot.png)
|
||||
--width/--height temporarily resize viewport for the shot
|
||||
snap Interactive elements with (x, y)
|
||||
text [selector] Visible text content
|
||||
|
||||
@@ -68,6 +69,8 @@ Flags:
|
||||
--tab <id> Stable Chrome target id (default: first page)
|
||||
--json JSON output
|
||||
--right/--double Right/double click
|
||||
--width <px> Screenshot viewport width
|
||||
--height <px> Screenshot viewport height
|
||||
--fps <n> Recording frame rate (default: 30)
|
||||
--scale <n> Recording scale factor (default: 1)`
|
||||
|
||||
|
||||
@@ -21,6 +21,15 @@ const parseNumericFlag = ({ name, value }: NumericFlagInput) => {
|
||||
return numeric
|
||||
}
|
||||
|
||||
const parseOptionalPositiveIntegerFlag = ({ name, value }: NumericFlagInput) => {
|
||||
if (value === undefined) return undefined
|
||||
const numeric = parseNumericFlag({ name, value })
|
||||
if (!Number.isInteger(numeric) || numeric <= 0) {
|
||||
throw new Error(`Invalid value for --${name}: "${String(value)}". Expected a positive integer.`)
|
||||
}
|
||||
return numeric
|
||||
}
|
||||
|
||||
const formatParseArgsError = ({ error }: FormatParseArgsErrorInput) => {
|
||||
const message = error instanceof Error ? error.message : String(error)
|
||||
const unknownFlag = message.match(/Unknown option '([^']+)'/)
|
||||
@@ -45,6 +54,8 @@ export const parse = (argv: string[]) => {
|
||||
help: { type: "boolean", short: "h", default: false },
|
||||
fps: { type: "string" },
|
||||
scale: { type: "string" },
|
||||
width: { type: "string" },
|
||||
height: { type: "string" },
|
||||
},
|
||||
})
|
||||
} catch (error) {
|
||||
@@ -65,6 +76,8 @@ export const parse = (argv: string[]) => {
|
||||
help: values.help!,
|
||||
fps: values.fps ? parseNumericFlag({ name: "fps", value: values.fps }) : undefined,
|
||||
scale: values.scale ? parseNumericFlag({ name: "scale", value: values.scale }) : undefined,
|
||||
width: parseOptionalPositiveIntegerFlag({ name: "width", value: values.width }),
|
||||
height: parseOptionalPositiveIntegerFlag({ name: "height", value: values.height }),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user