Skip to content

Commit

Permalink
make mod.ts simpler
Browse files Browse the repository at this point in the history
  • Loading branch information
ebebbington committed May 16, 2024
1 parent 7424cdc commit 627472e
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 76 deletions.
40 changes: 21 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,15 +47,15 @@ You use Sinco to build a subprocess (client) and interact with the page that has
been opened. This defaults to "about:blank".

```ts
import { build } from "...";
const { browser, page } = await build();
import { Client } from "...";
const { browser, page } = await Client.create();
```

The hostname and port of the subprocess and debugger default to `localhost` and
`9292` respectively. If you wish to customise this, you can:

```ts
await build({
await Client.create({
hostname: "127.0.0.1",
debuggerPort: 1000,
});
Expand All @@ -65,29 +65,31 @@ Be sure to always call `.close()` on the client once you've finished any actions
with it, to ensure you do not leave any hanging ops, For example, closing after
the last `browser.*` call or before assertions.

You can also use `connect()` if you wish to connect to an existing remote
process and not run a new subprocess yourself.
You can also use an existing remote process and not run a new subprocess
yourself.

````ts
import { connect } from "...";
const { browser, page } = await connect();
```ts
import { Client } from "...";
const { browser, page } = await Client.create({
remote: true,
});
```

### Visiting Pages

You can do this by calling `.location()` on the page:

```ts
const { browser, page } = await build();
const { browser, page } = await Client.create();
await page.location("https://some-url.com");
````
```

### Taking Screenshots

Utilise the `.screenshotMethod()` on a page or element:

```ts
const { browser, page } = await build();
const { browser, page } = await Client.create();
await page.location("https://some-url.com");
const uint8array = await page.screenshot({ // Options are optional
format: "jpeg", // or png. Defaults to jpeg
Expand All @@ -102,7 +104,7 @@ const uint8array = await elem.screenshot(); // Same options as above
You're able to interact with dialogs (prompt, alert).

```ts
const { browser, page } = await build();
const { browser, page } = await Client.create();
await page.location("https://some-url.com");
await page.dialog(false); // Decline the dialog
await page.dialog(true); // Accept it
Expand All @@ -114,7 +116,7 @@ await page.dialog(true, "I will be joining on 20/03/2024"); // Accept and provid
You can get or set cookies

```ts
const { browser, page } = await build();
const { browser, page } = await Client.create();
await page.location("https://some-url.com");
await page.cookie(); // Get the cookies, [ { ... }, { ... } ]
await page.cookie({
Expand All @@ -132,7 +134,7 @@ element and add it to a list, or get the `innerHTML` of an element, or get the
page title.

```ts
const { browser, page } = await build();
const { browser, page } = await Client.create();
await page.location("https://some-url.com");
await page.evaluate("1 + 1"); // 2
await page.evaluate(() => {
Expand All @@ -159,7 +161,7 @@ errors. `.consoleErrors()` will return any console errors that have appeared up
until this point.

```ts
const { browser, page } = await build();
const { browser, page } = await Client.create();
await page.location("https://some-url.com");
await page.evaluate("1 + 1"); // 2
const errors = await page.consoleErrors();
Expand Down Expand Up @@ -188,7 +190,7 @@ the browser.
We provide an easier way to set a file on a file input element.

```ts
const { browser, page } = await build();
const { browser, page } = await Client.create();
await page.location("https://some-url.com");
const input = await page.querySelector('input[type="file"]');
await input.file("./users.png");
Expand All @@ -201,7 +203,7 @@ await multipleInput.files(["./users.png", "./company.pdf"]);
You can also click elements, such as buttons or anchor tags.

```ts
const { browser, page } = await build();
const { browser, page } = await Client.create();
await page.location("https://some-url.com");
const button = await page.querySelector('button[type="button"]');
await button.click();
Expand All @@ -226,7 +228,7 @@ One way of authenticating, say if there is a website that is behind a login, is
to manually set some cookies e.g., `X-CSRF-TOKEN`:

```ts
const { browser, page } = await build();
const { browser, page } = await Client.create();
await page.location("https://some-url.com/login");
const token = await page.evaluate(() =>
document.querySelector('meta[name="token"]').value
Expand All @@ -241,7 +243,7 @@ await page.location("https://some-url.com/api/users");
Another approach would be to manually submit a login form:

```ts
const { browser, page } = await build();
const { browser, page } = await Client.create();
await page.location("https://some-url.com/login");
const button = await page.querySelector('[type="submit"]');
await page.evaluate(() =>
Expand Down
49 changes: 1 addition & 48 deletions mod.ts
Original file line number Diff line number Diff line change
@@ -1,53 +1,6 @@
import { Client } from "./src/client.ts";
import { BuildOptions, Cookie, ScreenshotOptions } from "./src/interfaces.ts";
import { Page } from "./src/page.ts";
import { getChromeArgs } from "./src/utility.ts";

export type { BuildOptions, Cookie, ScreenshotOptions };

const defaultOptions = {
hostname: "localhost",
debuggerPort: 9292,
binaryPath: undefined,
};

export async function build(
{
hostname = "localhost",
debuggerPort = 9292,
binaryPath,
}: BuildOptions = defaultOptions,
): Promise<{
browser: Client;
page: Page;
}> {
const buildArgs = getChromeArgs(debuggerPort, binaryPath);
const path = buildArgs.splice(0, 1)[0];
const command = new Deno.Command(path, {
args: buildArgs,
stderr: "piped",
stdout: "piped",
});
const browserProcess = command.spawn();

return await Client.create(
{
hostname,
port: debuggerPort,
},
browserProcess,
);
}

export async function connect({
hostname = "localhost",
debuggerPort = 9292,
}: BuildOptions = defaultOptions) {
console.log(hostname, debuggerPort);
return await Client.create(
{
hostname,
port: debuggerPort,
},
);
}
export { Client };
43 changes: 34 additions & 9 deletions src/client.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
import { deferred } from "../deps.ts";
import { BuildOptions, WebsocketTarget } from "./interfaces.ts";
import { Page } from "./page.ts";
import { getChromeArgs } from "./utility.ts";

const defaultOptions = {
hostname: "localhost",
debuggerPort: 9292,
binaryPath: undefined,
remote: false,
};

/**
* A way to interact with the headless browser instance.
Expand Down Expand Up @@ -104,24 +113,37 @@ export class Client {
* @returns A client and browser instance, ready to be used
*/
static async create(
wsOptions: {
hostname: string;
port: number;
},
browserProcess: Deno.ChildProcess | undefined = undefined,
{
hostname = "localhost",
debuggerPort = 9292,
binaryPath,
remote,
}: BuildOptions = defaultOptions,
): Promise<{
browser: Client;
page: Page;
}> {
let browserProcess: Deno.ChildProcess | undefined = undefined;

if (!remote) {
const buildArgs = getChromeArgs(debuggerPort, binaryPath);
const path = buildArgs.splice(0, 1)[0];
const command = new Deno.Command(path, {
args: buildArgs,
stderr: "piped",
stdout: "piped",
});
browserProcess = command.spawn();
}
// Wait until endpoint is ready and get a WS connection
// to the main socket
const p = deferred<WebSocket>();
const intervalId = setTimeout(async () => {
try {
const res = await fetch(
`http://${wsOptions.hostname}:${wsOptions.port}/json/version`,
`http://${hostname}:${debuggerPort}/json/version`,
);
const json = await res.json();
const json = await res.json() as WebsocketTarget;
const socket = new WebSocket(json["webSocketDebuggerUrl"]);
const p2 = deferred();
socket.onopen = () => p2.resolve();
Expand All @@ -136,14 +158,17 @@ export class Client {
const clientSocket = await p;

const listRes = await fetch(
`http://${wsOptions.hostname}:${wsOptions.port}/json/list`,
`http://${hostname}:${debuggerPort}/json/list`,
);
const targetId = (await listRes.json())[0]["id"];

const client = new Client(
clientSocket,
browserProcess,
wsOptions,
{
hostname,
port: debuggerPort,
},
);

// Handle CTRL+C for example
Expand Down
2 changes: 2 additions & 0 deletions src/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ export interface BuildOptions {
hostname?: string;
/** The path to the binary of the browser executable, such as specifying an alternative chromium browser */
binaryPath?: string;
/** If true, will not run a subprocess but will still connect to the ws endpoint using above info */
remote?: boolean;
}

export interface ScreenshotOptions {
Expand Down

0 comments on commit 627472e

Please sign in to comment.