diff --git a/deno.jsonc b/deno.jsonc index 627e9e3..326d746 100644 --- a/deno.jsonc +++ b/deno.jsonc @@ -36,5 +36,8 @@ "docs/static/icon.png", "bindings/celestial.ts" ] + }, + "lint": { + "exclude": ["docs"] } } diff --git a/docs/pages/showcase.tsx b/docs/pages/showcase.tsx index 55cf9f9..b2b3068 100644 --- a/docs/pages/showcase.tsx +++ b/docs/pages/showcase.tsx @@ -1,6 +1,6 @@ import { launch } from "../../mod.ts"; import type { PageProps } from "https://deno.land/x/pyro@0.6.1/page.ts"; -import { ensureFileSync } from "https://deno.land/std@0.215.0/fs/ensure_file.ts"; +import { ensureFileSync } from "@std/fs/ensure-file"; export const config = { title: "Showcase", diff --git a/src/locator.ts b/src/locator.ts index 8362534..5857aec 100644 --- a/src/locator.ts +++ b/src/locator.ts @@ -69,4 +69,37 @@ export class Locator { async wait(): Promise { return await this.#page.waitForSelector(this.#selector); } + + /** Creates a derived Locator for a descendant element. */ + locator(selector: string): Locator { + return new Locator( + this.#page, + `${this.#selector} ${selector}`, + this.#timeout, + ); + } + + /** + * Queries the locator for an element matching the given selector. + * + * @example + * ```ts + * const elementWithClass = await locator.$(".class"); + * ``` + */ + $(selector: string): Promise { + return this.#runLocator((handle) => handle.$(selector)); + } + + /** + * Queries the locator for all elements matching the given selector. + * + * @example + * ```ts + * const elementsWithClass = await locator.$$(".class"); + * ``` + */ + $$(selector: string): Promise { + return this.#runLocator((handle) => handle.$$(selector)); + } } diff --git a/tests/locator_test.ts b/tests/locator_test.ts index 162086c..a4eab28 100644 --- a/tests/locator_test.ts +++ b/tests/locator_test.ts @@ -1,5 +1,5 @@ /// -import { assertEquals } from "@std/assert"; +import { assertEquals, assertExists } from "@std/assert"; import { launch } from "../mod.ts"; import * as path from "@std/path"; @@ -101,3 +101,50 @@ Deno.test("Locator - fill()", async () => { await page.close(); await browser.close(); }); + +Deno.test("Locator - locator()", async () => { + await using server = await serveFixture("fixtures/wait_for_element.html"); + + await using browser = await launch(); + await using page = await browser.newPage(server.address); + const targetLocator = page.locator("#target"); + + const h1Locator = targetLocator.locator("h1"); + + const res = await h1Locator.evaluate((el) => { + return document.querySelector("h1") === el; + }); + assertEquals(res, true); +}); + +Deno.test("Locator - $()", async () => { + await using server = await serveFixture("fixtures/wait_for_element.html"); + + await using browser = await launch(); + await using page = await browser.newPage(server.address); + const targetLocator = page.locator("#target"); + + const h1El = await targetLocator.$("h1"); + assertExists(h1El); + + const res = await h1El.evaluate((el) => { + return document.querySelector("h1") === el; + }); + assertEquals(res, true); +}); + +Deno.test("Locator - $$()", async () => { + await using server = await serveFixture("fixtures/wait_for_element.html"); + + await using browser = await launch(); + await using page = await browser.newPage(server.address); + const targetLocator = page.locator("#target"); + + const children = await targetLocator.$$("h1"); + assertEquals(children.length, 1); + + const res = await children[0].evaluate((el) => { + return document.querySelector("h1") === el; + }); + assertEquals(res, true); +});