{"id":13395399,"url":"https://github.com/deepsweet/foxr","last_synced_at":"2025-10-01T00:31:58.728Z","repository":{"id":41797237,"uuid":"144125504","full_name":"deepsweet/foxr","owner":"deepsweet","description":"🦊 Node.js API to control Firefox","archived":true,"fork":false,"pushed_at":"2023-01-04T21:41:11.000Z","size":1556,"stargazers_count":795,"open_issues_count":32,"forks_count":19,"subscribers_count":12,"default_branch":"master","last_synced_at":"2024-05-12T02:33:11.386Z","etag":null,"topics":["firefox","headless","marionette","puppeteer","remote","selenium"],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/deepsweet.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":"license.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-08-09T08:45:28.000Z","updated_at":"2024-04-25T10:34:45.000Z","dependencies_parsed_at":"2023-02-02T21:01:01.382Z","dependency_job_id":null,"html_url":"https://github.com/deepsweet/foxr","commit_stats":null,"previous_names":[],"tags_count":16,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/deepsweet%2Ffoxr","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/deepsweet%2Ffoxr/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/deepsweet%2Ffoxr/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/deepsweet%2Ffoxr/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/deepsweet","download_url":"https://codeload.github.com/deepsweet/foxr/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":234803446,"owners_count":18889256,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["firefox","headless","marionette","puppeteer","remote","selenium"],"created_at":"2024-07-30T17:01:56.790Z","updated_at":"2025-10-01T00:31:58.381Z","avatar_url":"https://github.com/deepsweet.png","language":"TypeScript","readme":"# foxr\n\n[![npm](https://flat.badgen.net/npm/v/foxr)](https://www.npmjs.com/package/foxr) [![install size](https://flat.badgen.net/packagephobia/install/foxr)](https://packagephobia.now.sh/result?p=foxr) [![tests](https://flat.badgen.net/travis/deepsweet/foxr/master?label=tests)](https://travis-ci.org/deepsweet/foxr) [![coverage](https://flat.badgen.net/codecov/c/github/deepsweet/foxr/master)](https://codecov.io/github/deepsweet/foxr)\n\nNode.js API to control Firefox.\n\n\u003cimg src=\"logo.svg\" width=\"110\" height=\"110\" align=\"right\" alt=\"logo\"/\u003e\n\n* uses a built-in [Marionette](https://vakila.github.io/blog/marionette-act-i-automation/) through [remote protocol](https://firefox-source-docs.mozilla.org/testing/marionette/marionette/index.html)\n* no [Selenium WebDriver](https://github.com/SeleniumHQ/selenium/wiki/FirefoxDriver) is needed\n* works with [Headless mode](https://developer.mozilla.org/en-US/docs/Mozilla/Firefox/Headless_mode)\n* compatible subset of [Puppeteer](https://github.com/GoogleChrome/puppeteer) API\n\nAt this point Foxr is more a proof of concept, [work is pretty much in progress](https://github.com/deepsweet/foxr/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3Aenhancement).\n\n## Example\n\nRun a locally installed Firefox:\n\n```sh\n/path/to/firefox -headless -marionette -safe-mode\n```\n\nOr a [dockerized version](https://github.com/deepsweet/firefox-headless-remote):\n\n```sh\ndocker run -it --rm --shm-size 2g -p 2828:2828 deepsweet/firefox-headless-remote:68\n```\n\n```js\nimport foxr from 'foxr'\n// const foxr = require('foxr').default\n\n(async () =\u003e {\n  try {\n    const browser = await foxr.connect()\n    const page = await browser.newPage()\n\n    await page.goto('https://example.com')\n    await page.screenshot({ path: 'example.png' })\n    await browser.close()\n  } catch (error) {\n    console.error(error)\n  }\n})()\n```\n\n## Install\n\n```sh\nyarn add --dev foxr\n# or\nnpm install --save-dev foxr\n```\n\n## API\n\n### Foxr\n\n#### `connect`\n\nConnect to the Marionette endpoint.\n\n```ts\ntype TConnectOptions = {\n  host?: string,\n  port?: number,\n  defaultViewport?: {\n    width?: number,\n    height?: number\n  }\n}\n\nfoxr.connect(options?: TConnectOptions): Promise\u003cBrowser\u003e\n```\n\n* `host` – `'localhost'` by default\n* `port` – `2828` by default\n* `defaultViewport`\n  * `width` – `800` by default\n  * `height` – `600` by default\n\n#### `launch`\n\n```ts\ntype TLaunchOptions = {\n  args?: string[],\n  dumpio?: boolean,\n  executablePath: string,\n  headless?: boolean\n} \u0026 TConnectOptions\n\nfoxr.launch(options?: TLaunchOptions): Promise\u003cBrowser\u003e\n```\n\n* `args` – array of additional args, `['-marionette', '-safe-mode', '-no-remote']` by default\n* `dumpio` – print browser process stdout and stderr, `false` by default\n* `executablePath` – path to Firefox executable, required\n* `headless` – whether to run browser in headless mode, `true` by default\n\n### Browser\n\n#### `close`\n\n```ts\nbrowser.close(): Promise\u003cvoid\u003e\n```\n\n#### `disconnect`\n\n```ts\nbrowser.disconnect(): Promise\u003cvoid\u003e\n```\n\n#### `newPage`\n\n```ts\nbrowser.newPage(): Promise\u003cPage\u003e\n```\n\n#### `pages`\n\n```ts\nbrowser.pages(): Promise\u003cPage[]\u003e\n```\n\n#### `install`\n\n```ts\nbrowser.install(extensionPath: string, isTemporary: boolean): Promise\u003cstring | null\u003e\n```\n\n#### `uninstall`\n\n```ts\nbrowser.install(extensionId: string): Promise\u003cvoid\u003e\n```\n\n#### `getPref`\n\n```ts\nbrowser.getPref(pref: string, defaultBranch: boolean = false): Promise\u003cany\u003e\n```\n\n#### `setPref`\n\n```ts\nbrowser.setPref(pref: string, value: string | number | boolean, defaultBranch: boolean = false): Promise\u003cvoid\u003e\n```\n\n### Page\n\n#### `$`\n\n```ts\npage.$(selector: string): Promise\u003cElementHandle | null\u003e\n```\n\n#### `$$`\n\n```ts\npage.$$(selector: string): Promise\u003cElementHandle[]\u003e\n```\n\n#### `$eval`\n\n```ts\npage.$eval(selector: string, func: TSerializableFunction, ...args: TEvaluateArg[]): Promise\u003cTJsonValue | void\u003e\n```\n\n#### `$$eval`\n\n```ts\npage.$$eval(selector: string, func: TSerializableFunction, ...args: TEvaluateArg[]): Promise\u003cArray\u003cTJsonValue | void\u003e\u003e\n```\n\n#### `bringToFront`\n\n```ts\npage.bringToFront(): Promise\u003cvoid\u003e\n```\n\n#### `browser`\n\n```ts\npage.browser(): TBrowser\n```\n\n#### `close`\n\n```ts\npage.close(): Promise\u003cvoid\u003e\n```\n\n#### `content`\n\n```ts\npage.content(): Promise\u003cstring\u003e\n```\n\n#### `evaluate`\n\n```ts\npage.evaluate(target: string): Promise\u003cTJsonValue | void\u003e\npage.evaluate(target: TSerializableFunction, ...args: TEvaluateArg[]): Promise\u003cTJsonValue | void\u003e\n```\n\n#### `evaluateHandle`\n\n```ts\npage.evaluate(target: string): Promise\u003cJSHandle\u003e\npage.evaluate(target: TSerializableFunction, ...args: TEvaluateArg[]): Promise\u003cJSHandle\u003e\n```\n\n#### `focus`\n\n```ts\npage.focus(selector: string): Promise\u003cvoid\u003e\n```\n\n#### `goto`\n\n```ts\npage.goto(url: string): Promise\u003cvoid\u003e\n```\n\n#### `screenshot`\n\n```ts\npage.screenshot(options?: { path?: string }): Promise\u003cBuffer\u003e\n```\n\n#### `setContent`\n\n```ts\npage.setContent(html: string): Promise\u003cvoid\u003e\n```\n\n#### `title`\n\n```ts\npage.title(): Promise\u003cstring\u003e\n```\n\n#### `url`\n\n```ts\npage.url(): Promise\u003cstring\u003e\n```\n\n#### `viewport`\n\n```ts\npage.viewport(): Promise\u003c{ width: number, height: number }\u003e\n```\n\n### JSHandle\n\n…\n\n### ElementHandle\n\n#### `$`\n\n```ts\nelementHandle.$(selector: string): Promise\u003cElementHandle | null\u003e\n```\n\n#### `$$`\n\n```ts\nelementHandle.$$(selector: string): Promise\u003cElementHandle[]\u003e\n```\n\n#### `click`\n\n```ts\ntype TOptions = {\n  button?: 'left' | 'middle' | 'right',\n  clickCount?: number\n}\n\nelementHandle.click(options?: TOptions): Promise\u003cvoid\u003e\n```\n\n#### `focus`\n\n```ts\nelementHandle.focus(): Promise\u003cvoid\u003e\n```\n\n#### `hover`\n\n```ts\nelementHandle.hover(): Promise\u003cvoid\u003e\n```\n\n#### `press`\n\n```ts\nelementHandle.press(key: string): Promise\u003cvoid\u003e\n```\n\nWhere `key` is of the [possible keys](./src/keys.ts) or a single character.\n\n#### `screenshot`\n\n```ts\nelementHandle.screenshot(options?: { path?: string }): Promise\u003cBuffer\u003e\n```\n\n#### `type`\n\n```ts\nelementHandle.type(text: string): Promise\u003cvoid\u003e\n```\n\n## Development\n\nSee [my Start task runner preset](https://github.com/deepsweet/_/tree/master/packages/start-preset-node-ts-lib) for details.\n\n## References\n\n* Python Client: [API](https://marionette-client.readthedocs.io/en/latest/reference.html), [source](https://searchfox.org/mozilla-central/source/testing/marionette/client/)\n* Perl Client: [API](https://metacpan.org/pod/Firefox::Marionette), [source](https://metacpan.org/source/DDICK/Firefox-Marionette-0.57/lib/Firefox)\n* Node.js client (outdated): [source](https://github.com/mozilla-b2g/gaia/tree/master/tests/jsmarionette/client)\n* [Marionette Google Group](https://groups.google.com/forum/#!forum/mozilla.tools.marionette)\n","funding_links":[],"categories":["TypeScript","Related"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdeepsweet%2Ffoxr","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdeepsweet%2Ffoxr","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdeepsweet%2Ffoxr/lists"}