Skip to content
This repository has been archived by the owner on Sep 22, 2023. It is now read-only.

Commit

Permalink
feat(next-image-snapshot): Add Browsers API (#22)
Browse files Browse the repository at this point in the history
  • Loading branch information
kdy1 authored Aug 24, 2023
1 parent ea8bce5 commit 1782d72
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 42 deletions.
87 changes: 56 additions & 31 deletions packages/next-image-snapshot/lib/browser.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { RenderedPage, closeAll } from "./index.js";
import { NextTestServer } from "./next-server.js";
import { Builder, ThenableWebDriver } from "selenium-webdriver";
import { Builder, WebDriver } from "selenium-webdriver";
import chrome from "selenium-webdriver/chrome";
import firefox from "selenium-webdriver/firefox";
import safari from "selenium-webdriver/safari";
Expand All @@ -22,13 +22,66 @@ type BrowserOptions = {
edge?: Mapper<import("selenium-webdriver/edge").Options>;
};

/**
* Browser[] with some helper methods, including `close()` and `Symbol.asyncDispose`.
*/
export class Browsers {
constructor(public readonly browsers: readonly Browser[]) {}

/**
* Creates an array of browsers. This method will close all browsers if an error occurs.
*/
public static async all(
server: NextTestServer,
browsers: string[],
options?: BrowserOptions,
): Promise<Browsers> {
const built = await Promise.allSettled(
browsers.map((browser) => Browser.create(server, browser, options)),
);

// This will close all browsers if an error occurs.
if (built.some((result) => result.status === "rejected")) {
await closeAll(built.map((result) => "value" in result && result.value));
}

// `await` above will make this code path unreachable if an error occurs.

return new Browsers(
built.map((result) => {
if (result.status === "fulfilled") {
return result.value;
} else {
throw result.reason;
}
}),
);
}

public async [Symbol.asyncDispose]() {
await this.close();
}

public async close() {
await closeAll(this.browsers);
}

public get drivers(): WebDriver[] {
return this.browsers.map((browser) => browser.driver);
}

[Symbol.iterator]() {
return this.browsers[Symbol.iterator]();
}
}

/**
* An instance of browser which is bound to a [NextTestServer]
*/
export class Browser {
constructor(
private readonly server: NextTestServer,
public readonly driver: Awaited<ThenableWebDriver>,
public readonly driver: WebDriver,
public readonly name: string,
) {}

Expand Down Expand Up @@ -75,34 +128,6 @@ export class Browser {
return new Browser(server, driver, browser);
}

/**
* Creates an array of browsers. This method will close all browsers if an error occurs.
*/
public static async all(
server: NextTestServer,
browsers: string[],
options?: BrowserOptions,
): Promise<Browser[]> {
const built = await Promise.allSettled(
browsers.map((browser) => Browser.create(server, browser, options)),
);

// This will close all browsers if an error occurs.
if (built.some((result) => result.status === "rejected")) {
await closeAll(built.map((result) => "value" in result && result.value));
}

// `await` above will make this code path unreachable if an error occurs.

return built.map((result) => {
if (result.status === "fulfilled") {
return result.value;
} else {
throw result.reason;
}
});
}

public async load(pathname: string): Promise<RenderedPage> {
console.log(`Rendering ${pathname}...`);

Expand All @@ -112,7 +137,7 @@ export class Browser {
}

public async [Symbol.asyncDispose]() {
await this.driver.quit();
await this.close();
}

public async close() {
Expand Down
9 changes: 5 additions & 4 deletions packages/next-image-snapshot/lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ type Close =
/**
* Falsy values will be ignored.
*/
export type Closable = Close | Close[];
export type Closable = Close | Iterable<Close>;
/**
* Closes every disposable in order, while catching and aggregating all errors.
*
Expand All @@ -56,11 +56,12 @@ export async function closeAll(...disposables: Closable[]): Promise<void> {
try {
if (!disposable) continue;

if (Array.isArray(disposable)) {
await closeAll(...disposable);
} else {
if ("close" in disposable) {
await disposable.close();
continue;
}

await closeAll(...disposable);
} catch (e: unknown) {
errors.push(e);
}
Expand Down
14 changes: 7 additions & 7 deletions packages/next-image-snapshot/tests/browser.test.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
import { describe, it, beforeEach, afterEach, expect } from "@jest/globals";
import { NextTestServer } from "../lib/next-server.js";
import "jest-expect-image";
import { Browser } from "../lib/browser.js";
import { Browsers } from "../lib/browser.js";
import { closeAll } from "../lib/index.js";

describe("Browser", () => {
let server!: NextTestServer;
let browsers!: Browser[];
let browsers!: Browsers;

beforeEach(async () => {
server = await NextTestServer.create({
dir: "./examples/next-app",
dev: true,
});
browsers = await Browser.all(server, ["chrome"], {
browsers = await Browsers.all(server, ["chrome"], {
chrome: (options) => options.headless(),
firefox: (options) => options.headless(),
});
Expand All @@ -36,7 +36,7 @@ describe("Browser", () => {
});
});

describe("Browser.all()", () => {
describe("Browsers.all()", () => {
let server!: NextTestServer;

beforeEach(async () => {
Expand Down Expand Up @@ -66,7 +66,7 @@ describe("Browser.all()", () => {

describe("headless", () => {
it("should propagate to all browsers", async () => {
const browsers = await Browser.all(server, ["chrome"], {
const browsers = await Browsers.all(server, ["chrome"], {
common: {
headless: true,
},
Expand All @@ -88,14 +88,14 @@ describe("Browser.all()", () => {
describe("when a browser is not installed", () => {
it("should throw an error", async () => {
expect(
Browser.all(server, ["chrome", "unknown-browser"]),
Browsers.all(server, ["chrome", "unknown-browser"]),
).rejects.toBeInstanceOf(Error);
});

it("should close other browsers", async () => {
// TODO: Check browsers
try {
await Browser.all(server, ["chrome", "unknown-browser"]);
await Browsers.all(server, ["chrome", "unknown-browser"]);
} catch (e: unknown) {
console.log(e);
}
Expand Down

0 comments on commit 1782d72

Please sign in to comment.