/
Locator.ts
89 lines (73 loc) · 2.82 KB
/
Locator.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
import { LogicError } from '@serenity-js/core';
import { inspectedObject } from '@serenity-js/core/lib/io';
import * as util from 'util'; // eslint-disable-line unicorn/import-style
import type { PageElement } from './PageElement';
import { RootLocator } from './RootLocator';
import { ByCss, ById, ByTagName, type Selector } from './selectors';
/**
* {@apilink Locator} uses a {@apilink Selector} to locate a {@apilink PageElement} or {@apilink PageElements}
* within the {@apilink Page}.
*
* ## Learn more
* - {@apilink RootLocator}
* - {@apilink Page.locate}
* - {@apilink PageElement}
* - {@apilink PageElements}
*
* @group Models
*/
export abstract class Locator<Native_Element_Type, Native_Selector_Type = any>
extends RootLocator<Native_Element_Type>
{
protected constructor(
protected readonly parent: RootLocator<Native_Element_Type>,
public readonly selector: Selector,
) {
super();
}
public abstract nativeElement(): Promise<Native_Element_Type>;
public abstract allNativeElements(): Promise<Array<Native_Element_Type>>;
async switchToFrame(element: Native_Element_Type): Promise<void> {
await this.parent.switchToFrame(element);
}
async switchToParentFrame(): Promise<void> {
await this.parent.switchToParentFrame();
}
async switchToMainFrame(): Promise<void> {
await this.parent.switchToMainFrame();
}
protected abstract nativeSelector(): Native_Selector_Type;
abstract of(parent: RootLocator<Native_Element_Type>): Locator<Native_Element_Type>;
abstract closestTo(child: Locator<Native_Element_Type>): Locator<Native_Element_Type>;
abstract locate(child: Locator<Native_Element_Type>): Locator<Native_Element_Type>;
/**
* Expresses {@apilink ByCss}, {@apilink ById}, or {@apilink ByTagName} as a {@apilink ByCss} selector.
*
* @throws LogicError
* if the `selector` can't be expressed as {@apilink ByCss}
*
* @param selector
* @protected
*/
protected asCssSelector(selector: Selector): ByCss {
if (selector instanceof ByCss) {
return selector;
}
if (selector instanceof ById) {
return new ByCss(`#${ selector.value }`);
}
if (selector instanceof ByTagName) {
return new ByCss(`${ selector.value }`);
}
throw new LogicError(`${ selector } can't be expressed as a CSS selector`)
}
abstract element(): PageElement<Native_Element_Type>;
abstract allElements(): Promise<Array<PageElement<Native_Element_Type>>>;
toString(): string {
return this.selector.toString();
}
/**
* Custom [Node.js inspection method](https://nodejs.org/api/util.html#utilinspectcustom).
*/
[util.inspect.custom] = inspectedObject(this, [ 'parent' as keyof this, 'selector' ]);
}