Skip to content

Commit 8bc945a

Browse files
authored
feat: locator descendants (#171)
* feat(locator): Add locator(), $() and $$() methods to select descendants * chore: Update std import in showcase.tsx * chore: Exclude docs folder from lint checks
1 parent a176123 commit 8bc945a

File tree

4 files changed

+85
-2
lines changed

4 files changed

+85
-2
lines changed

deno.jsonc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,5 +36,8 @@
3636
"docs/static/icon.png",
3737
"bindings/celestial.ts"
3838
]
39+
},
40+
"lint": {
41+
"exclude": ["docs"]
3942
}
4043
}

docs/pages/showcase.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { launch } from "../../mod.ts";
22
import type { PageProps } from "https://deno.land/x/pyro@0.6.1/page.ts";
3-
import { ensureFileSync } from "https://deno.land/std@0.215.0/fs/ensure_file.ts";
3+
import { ensureFileSync } from "@std/fs/ensure-file";
44

55
export const config = {
66
title: "Showcase",

src/locator.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,4 +69,37 @@ export class Locator<T> {
6969
async wait(): Promise<ElementHandle> {
7070
return await this.#page.waitForSelector(this.#selector);
7171
}
72+
73+
/** Creates a derived Locator for a descendant element. */
74+
locator<T>(selector: string): Locator<T> {
75+
return new Locator(
76+
this.#page,
77+
`${this.#selector} ${selector}`,
78+
this.#timeout,
79+
);
80+
}
81+
82+
/**
83+
* Queries the locator for an element matching the given selector.
84+
*
85+
* @example
86+
* ```ts
87+
* const elementWithClass = await locator.$(".class");
88+
* ```
89+
*/
90+
$(selector: string): Promise<ElementHandle | null> {
91+
return this.#runLocator((handle) => handle.$(selector));
92+
}
93+
94+
/**
95+
* Queries the locator for all elements matching the given selector.
96+
*
97+
* @example
98+
* ```ts
99+
* const elementsWithClass = await locator.$$(".class");
100+
* ```
101+
*/
102+
$$(selector: string): Promise<ElementHandle[]> {
103+
return this.#runLocator((handle) => handle.$$(selector));
104+
}
72105
}

tests/locator_test.ts

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/// <reference lib="dom" />
2-
import { assertEquals } from "@std/assert";
2+
import { assertEquals, assertExists } from "@std/assert";
33
import { launch } from "../mod.ts";
44
import * as path from "@std/path";
55

@@ -101,3 +101,50 @@ Deno.test("Locator - fill()", async () => {
101101
await page.close();
102102
await browser.close();
103103
});
104+
105+
Deno.test("Locator - locator()", async () => {
106+
await using server = await serveFixture("fixtures/wait_for_element.html");
107+
108+
await using browser = await launch();
109+
await using page = await browser.newPage(server.address);
110+
const targetLocator = page.locator<HTMLDivElement>("#target");
111+
112+
const h1Locator = targetLocator.locator<HTMLHeadingElement>("h1");
113+
114+
const res = await h1Locator.evaluate((el) => {
115+
return document.querySelector("h1") === el;
116+
});
117+
assertEquals(res, true);
118+
});
119+
120+
Deno.test("Locator - $()", async () => {
121+
await using server = await serveFixture("fixtures/wait_for_element.html");
122+
123+
await using browser = await launch();
124+
await using page = await browser.newPage(server.address);
125+
const targetLocator = page.locator<HTMLDivElement>("#target");
126+
127+
const h1El = await targetLocator.$("h1");
128+
assertExists(h1El);
129+
130+
const res = await h1El.evaluate((el) => {
131+
return document.querySelector("h1") === el;
132+
});
133+
assertEquals(res, true);
134+
});
135+
136+
Deno.test("Locator - $$()", async () => {
137+
await using server = await serveFixture("fixtures/wait_for_element.html");
138+
139+
await using browser = await launch();
140+
await using page = await browser.newPage(server.address);
141+
const targetLocator = page.locator<HTMLDivElement>("#target");
142+
143+
const children = await targetLocator.$$("h1");
144+
assertEquals(children.length, 1);
145+
146+
const res = await children[0].evaluate((el) => {
147+
return document.querySelector("h1") === el;
148+
});
149+
assertEquals(res, true);
150+
});

0 commit comments

Comments
 (0)