@serenity-js/web 3.9.1 → 3.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +19 -0
- package/lib/screenplay/models/Page.d.ts.map +1 -1
- package/lib/screenplay/models/Page.js.map +1 -1
- package/lib/screenplay/models/PageElement.d.ts +3 -3
- package/lib/screenplay/models/PageElement.d.ts.map +1 -1
- package/lib/screenplay/models/PageElement.js.map +1 -1
- package/lib/screenplay/models/PageElements.d.ts +6 -16
- package/lib/screenplay/models/PageElements.d.ts.map +1 -1
- package/lib/screenplay/models/PageElements.js +5 -60
- package/lib/screenplay/models/PageElements.js.map +1 -1
- package/lib/screenplay/models/PageElementsLocator.d.ts +19 -0
- package/lib/screenplay/models/PageElementsLocator.d.ts.map +1 -0
- package/lib/screenplay/models/PageElementsLocator.js +41 -0
- package/lib/screenplay/models/PageElementsLocator.js.map +1 -0
- package/lib/screenplay/models/index.d.ts +1 -0
- package/lib/screenplay/models/index.d.ts.map +1 -1
- package/lib/screenplay/models/index.js +1 -0
- package/lib/screenplay/models/index.js.map +1 -1
- package/lib/screenplay/questions/Attribute.d.ts +1 -1
- package/lib/screenplay/questions/Attribute.d.ts.map +1 -1
- package/lib/screenplay/questions/CssClasses.d.ts +2 -31
- package/lib/screenplay/questions/CssClasses.d.ts.map +1 -1
- package/lib/screenplay/questions/CssClasses.js +11 -48
- package/lib/screenplay/questions/CssClasses.js.map +1 -1
- package/lib/screenplay/questions/Text.d.ts +2 -1
- package/lib/screenplay/questions/Text.d.ts.map +1 -1
- package/lib/screenplay/questions/Text.js +11 -71
- package/lib/screenplay/questions/Text.js.map +1 -1
- package/lib/screenplay/questions/Value.d.ts +2 -30
- package/lib/screenplay/questions/Value.d.ts.map +1 -1
- package/lib/screenplay/questions/Value.js +5 -41
- package/lib/screenplay/questions/Value.js.map +1 -1
- package/package.json +5 -5
- package/src/screenplay/models/Page.ts +1 -0
- package/src/screenplay/models/PageElement.ts +5 -5
- package/src/screenplay/models/PageElements.ts +8 -91
- package/src/screenplay/models/PageElementsLocator.ts +57 -0
- package/src/screenplay/models/index.ts +1 -0
- package/src/screenplay/questions/Attribute.ts +1 -1
- package/src/screenplay/questions/CssClasses.ts +17 -58
- package/src/screenplay/questions/Text.ts +22 -100
- package/src/screenplay/questions/Value.ts +10 -51
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Text.js","sourceRoot":"","sources":["../../../src/screenplay/questions/Text.ts"],"names":[],"mappings":";;;AACA,4CAAgD;AAChD,iDAAoD;
|
|
1
|
+
{"version":3,"file":"Text.js","sourceRoot":"","sources":["../../../src/screenplay/questions/Text.ts"],"names":[],"mappings":";;;AACA,4CAAgD;AAChD,iDAAoD;AAGpD,sCAAwC;AAExC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsFG;AACH,MAAa,IAAI;IAEb;;;;;;;;;OASG;IACH,MAAM,CAAC,EAAE,CAAC,WAAuD;QAC7D,OAAO,eAAQ,CAAC,KAAK,CAAC,IAAA,QAAC,EAAA,eAAgB,WAAY,EAAE,EACjD,KAAK,EAAC,KAAK,EAAC,EAAE;YACV,MAAM,OAAO,GAAG,MAAM,KAAK,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;YAEhD,OAAO,OAAO,CAAC,IAAI,EAAE,CAAC;QAC1B,CAAC,EACD,CAAC,MAA+B,EAAE,EAAE,CAChC,IAAI,CAAC,EAAE,CAAC,oBAAW,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC,CACnD,CAAC;IACN,CAAC;IAcD,MAAM,CAAC,KAAK,CAAC,YAAsD;QAC/D,IAAI,eAAQ,CAAC,eAAe,CAAC,YAAY,CAAC,EAAE;YACxC,OAAO,eAAQ,CAAC,KAAK,CAAC,IAAA,QAAC,EAAA,eAAgB,YAAa,EAAE,EAClD,cAAc,CAAC,YAAY,CAAC,EAC5B,CAAC,MAA+B,EAAE,EAAE,CAChC,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAC1C,CAAC;SACL;QAED,OAAO,eAAQ,CAAC,KAAK,CAAC,IAAA,QAAC,EAAA,eAAgB,YAAa,EAAE,EAAE,cAAc,CAAC,YAAY,CAAC,CAAC,CAAC;IAC1F,CAAC;CACJ;AA/CD,oBA+CC;AAED,SAAS,cAAc,CAAC,YAAuC;IAC3D,OAAO,KAAK,EAAE,KAAuB,EAAE,EAAE;QACrC,MAAM,QAAQ,GAAkB,MAAM,KAAK,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;QACjE,OAAO,IAAA,aAAQ,EAAC,QAAQ,EAAE,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;IACzD,CAAC,CAAA;AACL,CAAC"}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import { Question } from '@serenity-js/core';
|
|
1
|
+
import type { MetaQuestionAdapter, QuestionAdapter } from '@serenity-js/core';
|
|
3
2
|
import { PageElement } from '../models';
|
|
4
3
|
/**
|
|
5
4
|
* Uses the {@apilink Actor|actor's} {@apilink Ability|ability} to {@apilink BrowseTheWeb} to retrieve
|
|
@@ -55,9 +54,7 @@ import { PageElement } from '../models';
|
|
|
55
54
|
*
|
|
56
55
|
* @group Questions
|
|
57
56
|
*/
|
|
58
|
-
export declare class Value
|
|
59
|
-
private readonly element;
|
|
60
|
-
private subject;
|
|
57
|
+
export declare class Value {
|
|
61
58
|
/**
|
|
62
59
|
* Instantiates a {@apilink Question} that uses
|
|
63
60
|
* the {@apilink Actor|actor's} {@apilink Ability|ability} to {@apilink BrowseTheWeb} to retrieve
|
|
@@ -69,30 +66,5 @@ export declare class Value extends Question<Promise<string>> implements MetaQues
|
|
|
69
66
|
* @param pageElement
|
|
70
67
|
*/
|
|
71
68
|
static of(pageElement: QuestionAdapter<PageElement> | PageElement): MetaQuestionAdapter<PageElement, string>;
|
|
72
|
-
protected constructor(element: QuestionAdapter<PageElement> | PageElement);
|
|
73
|
-
/**
|
|
74
|
-
* Instantiates a {@apilink Question} that uses
|
|
75
|
-
* the {@apilink Actor|actor's} {@apilink Ability|ability} to {@apilink BrowseTheWeb} to retrieve
|
|
76
|
-
* the `value` attribute of a given {@apilink PageElement}
|
|
77
|
-
* located within the `parent` element.
|
|
78
|
-
*
|
|
79
|
-
* #### Learn more
|
|
80
|
-
* - {@apilink MetaQuestion}
|
|
81
|
-
*
|
|
82
|
-
* @param parent
|
|
83
|
-
*/
|
|
84
|
-
of(parent: QuestionAdapter<PageElement> | PageElement): Question<Promise<string>>;
|
|
85
|
-
/**
|
|
86
|
-
* @inheritDoc
|
|
87
|
-
*/
|
|
88
|
-
answeredBy(actor: AnswersQuestions & UsesAbilities): Promise<string>;
|
|
89
|
-
/**
|
|
90
|
-
* @inheritDoc
|
|
91
|
-
*/
|
|
92
|
-
describedAs(subject: string): this;
|
|
93
|
-
/**
|
|
94
|
-
* @inheritDoc
|
|
95
|
-
*/
|
|
96
|
-
toString(): string;
|
|
97
69
|
}
|
|
98
70
|
//# sourceMappingURL=Value.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Value.d.ts","sourceRoot":"","sources":["../../../src/screenplay/questions/Value.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"Value.d.ts","sourceRoot":"","sources":["../../../src/screenplay/questions/Value.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAa,mBAAmB,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAGzF,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAExC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqDG;AACH,qBAAa,KAAK;IAEd;;;;;;;;;OASG;IACH,MAAM,CAAC,EAAE,CAAC,WAAW,EAAE,eAAe,CAAC,WAAW,CAAC,GAAG,WAAW,GAAG,mBAAmB,CAAC,WAAW,EAAE,MAAM,CAAC;CAU/G"}
|
|
@@ -57,7 +57,7 @@ const models_1 = require("../models");
|
|
|
57
57
|
*
|
|
58
58
|
* @group Questions
|
|
59
59
|
*/
|
|
60
|
-
class Value
|
|
60
|
+
class Value {
|
|
61
61
|
/**
|
|
62
62
|
* Instantiates a {@apilink Question} that uses
|
|
63
63
|
* the {@apilink Actor|actor's} {@apilink Ability|ability} to {@apilink BrowseTheWeb} to retrieve
|
|
@@ -69,46 +69,10 @@ class Value extends core_1.Question {
|
|
|
69
69
|
* @param pageElement
|
|
70
70
|
*/
|
|
71
71
|
static of(pageElement) {
|
|
72
|
-
return core_1.Question.
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
this.element = element;
|
|
77
|
-
this.subject = (0, core_1.d) `the value of ${element}`;
|
|
78
|
-
}
|
|
79
|
-
/**
|
|
80
|
-
* Instantiates a {@apilink Question} that uses
|
|
81
|
-
* the {@apilink Actor|actor's} {@apilink Ability|ability} to {@apilink BrowseTheWeb} to retrieve
|
|
82
|
-
* the `value` attribute of a given {@apilink PageElement}
|
|
83
|
-
* located within the `parent` element.
|
|
84
|
-
*
|
|
85
|
-
* #### Learn more
|
|
86
|
-
* - {@apilink MetaQuestion}
|
|
87
|
-
*
|
|
88
|
-
* @param parent
|
|
89
|
-
*/
|
|
90
|
-
of(parent) {
|
|
91
|
-
return new Value(models_1.PageElement.of(this.element, parent));
|
|
92
|
-
}
|
|
93
|
-
/**
|
|
94
|
-
* @inheritDoc
|
|
95
|
-
*/
|
|
96
|
-
async answeredBy(actor) {
|
|
97
|
-
const element = await actor.answer(this.element);
|
|
98
|
-
return element.value();
|
|
99
|
-
}
|
|
100
|
-
/**
|
|
101
|
-
* @inheritDoc
|
|
102
|
-
*/
|
|
103
|
-
describedAs(subject) {
|
|
104
|
-
this.subject = subject;
|
|
105
|
-
return this;
|
|
106
|
-
}
|
|
107
|
-
/**
|
|
108
|
-
* @inheritDoc
|
|
109
|
-
*/
|
|
110
|
-
toString() {
|
|
111
|
-
return this.subject;
|
|
72
|
+
return core_1.Question.about((0, core_1.d) `the value of ${pageElement}`, async (actor) => {
|
|
73
|
+
const element = await actor.answer(pageElement);
|
|
74
|
+
return element.value();
|
|
75
|
+
}, (parent) => Value.of(models_1.PageElement.of(pageElement, parent)));
|
|
112
76
|
}
|
|
113
77
|
}
|
|
114
78
|
exports.Value = Value;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Value.js","sourceRoot":"","sources":["../../../src/screenplay/questions/Value.ts"],"names":[],"mappings":";;;AACA,4CAAgD;AAEhD,sCAAwC;AAExC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqDG;AACH,MAAa,
|
|
1
|
+
{"version":3,"file":"Value.js","sourceRoot":"","sources":["../../../src/screenplay/questions/Value.ts"],"names":[],"mappings":";;;AACA,4CAAgD;AAEhD,sCAAwC;AAExC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqDG;AACH,MAAa,KAAK;IAEd;;;;;;;;;OASG;IACH,MAAM,CAAC,EAAE,CAAC,WAAuD;QAC7D,OAAO,eAAQ,CAAC,KAAK,CAAC,IAAA,QAAC,EAAA,gBAAiB,WAAY,EAAE,EAClD,KAAK,EAAC,KAAK,EAAC,EAAE;YACV,MAAM,OAAO,GAAG,MAAM,KAAK,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;YAChD,OAAO,OAAO,CAAC,KAAK,EAAE,CAAC;QAC3B,CAAC,EACD,CAAC,MAA+B,EAAE,EAAE,CAChC,KAAK,CAAC,EAAE,CAAC,oBAAW,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC,CACpD,CAAC;IACN,CAAC;CACJ;AAtBD,sBAsBC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@serenity-js/web",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.10.1",
|
|
4
4
|
"description": "Serenity/JS Screenplay Pattern APIs for the Web",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Jan Molak",
|
|
@@ -44,8 +44,8 @@
|
|
|
44
44
|
"node": "^16.13 || ^18.12 || ^20"
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
|
-
"@serenity-js/assertions": "3.
|
|
48
|
-
"@serenity-js/core": "3.
|
|
47
|
+
"@serenity-js/assertions": "3.10.1",
|
|
48
|
+
"@serenity-js/core": "3.10.1",
|
|
49
49
|
"tiny-types": "^1.20.0"
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
"mocha": "^10.2.0",
|
|
57
57
|
"mocha-multi": "^1.1.7",
|
|
58
58
|
"ts-node": "^10.9.1",
|
|
59
|
-
"typescript": "
|
|
59
|
+
"typescript": "5.1.6"
|
|
60
60
|
},
|
|
61
|
-
"gitHead": "
|
|
61
|
+
"gitHead": "7ab90f30b17ed745cad713363a27edfd7cdce08a"
|
|
62
62
|
}
|
|
@@ -276,6 +276,7 @@ export abstract class Page<Native_Element_Type = any> implements Optional, Switc
|
|
|
276
276
|
*
|
|
277
277
|
* @param selector
|
|
278
278
|
*/
|
|
279
|
+
// abstract locateAll(selector: Selector): PageElements<Native_Element_Type>;
|
|
279
280
|
abstract locateAll(selector: Selector): PageElements<Native_Element_Type>;
|
|
280
281
|
|
|
281
282
|
/**
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Answerable,
|
|
1
|
+
import type { Answerable, MetaQuestionAdapter, Optional } from '@serenity-js/core';
|
|
2
2
|
import { d, Question } from '@serenity-js/core';
|
|
3
3
|
import { ensure, isDefined } from 'tiny-types';
|
|
4
4
|
|
|
@@ -22,21 +22,21 @@ import type { SwitchableOrigin } from './SwitchableOrigin';
|
|
|
22
22
|
*/
|
|
23
23
|
export abstract class PageElement<Native_Element_Type = any> implements Optional, Switchable {
|
|
24
24
|
|
|
25
|
-
static from<NET>(nativeElement: NET):
|
|
25
|
+
static from<NET>(nativeElement: NET): MetaQuestionAdapter<PageElement<NET>, PageElement<NET>> {
|
|
26
26
|
return Question.about(`native page element`, async actor => {
|
|
27
27
|
const currentPage = await BrowseTheWeb.as<BrowseTheWeb<NET>>(actor).currentPage();
|
|
28
28
|
|
|
29
29
|
return currentPage.createPageElement(nativeElement);
|
|
30
|
-
})
|
|
30
|
+
});
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
static located<NET>(selector: Answerable<Selector>):
|
|
33
|
+
static located<NET>(selector: Answerable<Selector>): MetaQuestionAdapter<PageElement<NET>, PageElement<NET>> {
|
|
34
34
|
return Question.about(d`page element located ${ selector }`, async actor => {
|
|
35
35
|
const bySelector = await actor.answer(selector);
|
|
36
36
|
const currentPage = await BrowseTheWeb.as<BrowseTheWeb<NET>>(actor).currentPage();
|
|
37
37
|
|
|
38
38
|
return currentPage.locate(bySelector);
|
|
39
|
-
})
|
|
39
|
+
});
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
static of<NET>(
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import type { Answerable
|
|
2
|
-
import {
|
|
1
|
+
import type { Answerable } from '@serenity-js/core';
|
|
2
|
+
import { MetaList } from '@serenity-js/core';
|
|
3
3
|
|
|
4
|
-
import { BrowseTheWeb } from '../abilities';
|
|
5
|
-
import type { Locator } from './Locator';
|
|
6
4
|
import type { PageElement } from './PageElement';
|
|
5
|
+
import { PageElementsLocator } from './PageElementsLocator';
|
|
7
6
|
import type { Selector } from './selectors';
|
|
8
7
|
|
|
9
8
|
/**
|
|
@@ -13,98 +12,16 @@ import type { Selector } from './selectors';
|
|
|
13
12
|
* ## Learn more
|
|
14
13
|
*
|
|
15
14
|
* - [Page Element Query Language](/handbook/web-testing/page-element-query-language)
|
|
15
|
+
* - {@apilink MetaList}
|
|
16
16
|
* - {@apilink List}
|
|
17
|
-
* - {@apilink
|
|
17
|
+
* - {@apilink ChainableMetaQuestion}
|
|
18
18
|
*
|
|
19
19
|
* @group Models
|
|
20
20
|
*/
|
|
21
21
|
export class PageElements<Native_Element_Type = any>
|
|
22
|
-
extends
|
|
23
|
-
implements MetaQuestion<PageElement<Native_Element_Type>, Promise<Array<PageElement<Native_Element_Type>>>>
|
|
22
|
+
extends MetaList<PageElement<Native_Element_Type>, PageElement<Native_Element_Type>>
|
|
24
23
|
{
|
|
25
|
-
static located<NET>(selector: Answerable<Selector>): PageElements
|
|
26
|
-
return new PageElements(
|
|
24
|
+
static located<NET>(selector: Answerable<Selector>): PageElements {
|
|
25
|
+
return new PageElements(PageElementsLocator.fromDocumentRoot<NET>(selector));
|
|
27
26
|
}
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* @param locator
|
|
31
|
-
*/
|
|
32
|
-
constructor(protected readonly locator: Answerable<Locator<Native_Element_Type>>) {
|
|
33
|
-
super(allElementsOf(locator));
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
of(parent: Answerable<PageElement<Native_Element_Type>>): PageElements<Native_Element_Type> {
|
|
37
|
-
return new PageElements<Native_Element_Type>(relativeToParent(this.locator, parent))
|
|
38
|
-
.describedAs(`${ this.toString() } of ${ parent }`);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
override count(): MetaQuestionAdapter<PageElement<Native_Element_Type>, number> {
|
|
42
|
-
const count = super.count();
|
|
43
|
-
return Question.about(
|
|
44
|
-
count.toString(),
|
|
45
|
-
actor => actor.answer(count),
|
|
46
|
-
(parent: Answerable<PageElement>) => this.of(parent).count(),
|
|
47
|
-
);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
override first(): MetaQuestionAdapter<PageElement<Native_Element_Type>, PageElement<Native_Element_Type>> {
|
|
51
|
-
const first = super.first();
|
|
52
|
-
return Question.about<PageElement, PageElement>(
|
|
53
|
-
first.toString(),
|
|
54
|
-
async actor => actor.answer(first),
|
|
55
|
-
(parent: Answerable<PageElement>) => this.of(parent).first(),
|
|
56
|
-
);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
override last(): MetaQuestionAdapter<PageElement<Native_Element_Type>, PageElement<Native_Element_Type>> {
|
|
60
|
-
const last = super.last();
|
|
61
|
-
return Question.about<PageElement, PageElement>(
|
|
62
|
-
last.toString(),
|
|
63
|
-
async actor => actor.answer(last),
|
|
64
|
-
(parent: Answerable<PageElement>) => this.of(parent).last(),
|
|
65
|
-
);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
override nth(index: number): MetaQuestionAdapter<PageElement<Native_Element_Type>, PageElement<Native_Element_Type>> {
|
|
69
|
-
const nth = super.nth(index);
|
|
70
|
-
return Question.about<PageElement, PageElement>(
|
|
71
|
-
nth.toString(),
|
|
72
|
-
async actor => actor.answer(nth),
|
|
73
|
-
(parent: Answerable<PageElement>) => this.of(parent).nth(index),
|
|
74
|
-
);
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* @package
|
|
80
|
-
*/
|
|
81
|
-
function relativeToDocumentRoot<Native_Element_Type>(selector: Answerable<Selector>): Question<Promise<Locator<Native_Element_Type>>> {
|
|
82
|
-
return Question.about(String(selector), async actor => {
|
|
83
|
-
const bySelector = await actor.answer(selector);
|
|
84
|
-
const currentPage = await BrowseTheWeb.as<BrowseTheWeb<Native_Element_Type>>(actor).currentPage();
|
|
85
|
-
|
|
86
|
-
return currentPage.locate(bySelector).locator;
|
|
87
|
-
});
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* @package
|
|
92
|
-
*/
|
|
93
|
-
function relativeToParent<Native_Element_Type>(relativeLocator: Answerable<Locator<Native_Element_Type>>, parent: Answerable<PageElement<Native_Element_Type>>): Question<Promise<Locator<Native_Element_Type>>> {
|
|
94
|
-
return Question.about(`${ relativeLocator.toString() } of ${ parent }`, async actor => {
|
|
95
|
-
const locator: Locator<Native_Element_Type> = await actor.answer(relativeLocator);
|
|
96
|
-
const parentElement: PageElement<Native_Element_Type> = await actor.answer(parent);
|
|
97
|
-
|
|
98
|
-
return locator.of(parentElement.locator);
|
|
99
|
-
});
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
/**
|
|
103
|
-
* @package
|
|
104
|
-
*/
|
|
105
|
-
function allElementsOf<Native_Element_Type>(locator: Answerable<Locator<Native_Element_Type>>): Question<Promise<Array<PageElement<Native_Element_Type>>>> {
|
|
106
|
-
return Question.about(`page elements located ${ String(locator) }`, async actor => {
|
|
107
|
-
const resolved: Locator<Native_Element_Type> = await actor.answer(locator);
|
|
108
|
-
return resolved.allElements();
|
|
109
|
-
});
|
|
110
27
|
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { Answerable, AnswersQuestions, ChainableMetaQuestion, UsesAbilities } from '@serenity-js/core';
|
|
2
|
+
import { d, Question } from '@serenity-js/core';
|
|
3
|
+
|
|
4
|
+
import { BrowseTheWeb } from '../abilities';
|
|
5
|
+
import type { Locator } from './Locator';
|
|
6
|
+
import type { PageElement } from './PageElement';
|
|
7
|
+
import type { Selector } from './selectors';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @group Models
|
|
11
|
+
*/
|
|
12
|
+
export class PageElementsLocator<Native_Element_Type = any>
|
|
13
|
+
extends Question<Promise<Array<PageElement<Native_Element_Type>>>>
|
|
14
|
+
implements ChainableMetaQuestion<PageElement<Native_Element_Type>, Question<Promise<Array<PageElement<Native_Element_Type>>>>>
|
|
15
|
+
{
|
|
16
|
+
static fromDocumentRoot<NET>(selector: Answerable<Selector>): PageElementsLocator<NET> {
|
|
17
|
+
return new PageElementsLocator(
|
|
18
|
+
Question.about(d`page elements located ${ selector }`, async actor => {
|
|
19
|
+
const bySelector = await actor.answer(selector);
|
|
20
|
+
const currentPage = await BrowseTheWeb.as<BrowseTheWeb<NET>>(actor).currentPage();
|
|
21
|
+
|
|
22
|
+
return currentPage.locate(bySelector).locator;
|
|
23
|
+
})
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
private subject?: string;
|
|
28
|
+
|
|
29
|
+
constructor(private readonly locator: Answerable<Locator<Native_Element_Type>>) {
|
|
30
|
+
super();
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
of(parent: Answerable<PageElement<Native_Element_Type>>): Question<Promise<Array<PageElement<Native_Element_Type>>>> & ChainableMetaQuestion<PageElement<Native_Element_Type>, Question<Promise<Array<PageElement<Native_Element_Type>>>>> {
|
|
34
|
+
return new PageElementsLocator(
|
|
35
|
+
Question.about(this.toString() + d` of ${ parent }`, async actor => {
|
|
36
|
+
const locator: Locator<Native_Element_Type> = await actor.answer(this.locator);
|
|
37
|
+
const parentElement: PageElement<Native_Element_Type> = await actor.answer(parent);
|
|
38
|
+
|
|
39
|
+
return locator.of(parentElement.locator);
|
|
40
|
+
})
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async answeredBy(actor: AnswersQuestions & UsesAbilities): Promise<Array<PageElement<Native_Element_Type>>> {
|
|
45
|
+
const resolved: Locator<Native_Element_Type> = await actor.answer(this.locator);
|
|
46
|
+
return resolved.allElements();
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
describedAs(subject: string): this {
|
|
50
|
+
this.subject = subject;
|
|
51
|
+
return this;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
toString(): string {
|
|
55
|
+
return this.subject ?? d`${ this.locator }`;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -97,7 +97,7 @@ import { PageElement } from '../models';
|
|
|
97
97
|
*/
|
|
98
98
|
export class Attribute
|
|
99
99
|
extends Question<Promise<string>>
|
|
100
|
-
implements MetaQuestion<PageElement, string
|
|
100
|
+
implements MetaQuestion<PageElement, Question<Promise<string>>>
|
|
101
101
|
{
|
|
102
102
|
private subject: string;
|
|
103
103
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { Answerable,MetaQuestionAdapter, QuestionAdapter } from '@serenity-js/core';
|
|
2
2
|
import { d, Question } from '@serenity-js/core';
|
|
3
3
|
|
|
4
4
|
import { PageElement } from '../models';
|
|
@@ -96,11 +96,7 @@ import { PageElement } from '../models';
|
|
|
96
96
|
*
|
|
97
97
|
* @group Questions
|
|
98
98
|
*/
|
|
99
|
-
export class CssClasses
|
|
100
|
-
extends Question<Promise<string[]>>
|
|
101
|
-
implements MetaQuestion<PageElement, string[]>
|
|
102
|
-
{
|
|
103
|
-
private subject: string;
|
|
99
|
+
export class CssClasses {
|
|
104
100
|
|
|
105
101
|
/**
|
|
106
102
|
* Instantiates a {@apilink Question} that uses
|
|
@@ -114,58 +110,21 @@ export class CssClasses
|
|
|
114
110
|
* @param pageElement
|
|
115
111
|
*/
|
|
116
112
|
static of(pageElement: QuestionAdapter<PageElement> | PageElement): MetaQuestionAdapter<PageElement, string[]> {
|
|
117
|
-
return Question.
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
protected constructor(private readonly pageElement: QuestionAdapter<PageElement> | PageElement) {
|
|
121
|
-
super();
|
|
122
|
-
this.subject = d`CSS classes of ${ pageElement}`;
|
|
123
|
-
}
|
|
113
|
+
return Question.about(d`CSS classes of ${ pageElement }`,
|
|
114
|
+
async actor => {
|
|
115
|
+
const element = await actor.answer(pageElement);
|
|
124
116
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
of(parent: QuestionAdapter<PageElement> | PageElement): Question<Promise<string[]>> {
|
|
138
|
-
return new CssClasses(PageElement.of(this.pageElement, parent));
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
/**
|
|
142
|
-
* @inheritDoc
|
|
143
|
-
*/
|
|
144
|
-
async answeredBy(actor: AnswersQuestions & UsesAbilities): Promise<string[]> {
|
|
145
|
-
const element = await actor.answer(this.pageElement);
|
|
146
|
-
|
|
147
|
-
return element.attribute('class')
|
|
148
|
-
.then(attribute => attribute ?? '')
|
|
149
|
-
.then(attribute => attribute
|
|
150
|
-
.replace(/\s+/, ' ')
|
|
151
|
-
.trim()
|
|
152
|
-
.split(' ')
|
|
153
|
-
.filter(cssClass => !! cssClass),
|
|
154
|
-
);
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
/**
|
|
158
|
-
* @inheritDoc
|
|
159
|
-
*/
|
|
160
|
-
describedAs(subject: string): this {
|
|
161
|
-
this.subject = subject;
|
|
162
|
-
return this;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
/**
|
|
166
|
-
* @inheritDoc
|
|
167
|
-
*/
|
|
168
|
-
toString(): string {
|
|
169
|
-
return this.subject;
|
|
117
|
+
return element.attribute('class')
|
|
118
|
+
.then(attribute => attribute ?? '')
|
|
119
|
+
.then(attribute => attribute
|
|
120
|
+
.replace(/\s+/, ' ')
|
|
121
|
+
.trim()
|
|
122
|
+
.split(' ')
|
|
123
|
+
.filter(cssClass => !! cssClass),
|
|
124
|
+
);
|
|
125
|
+
},
|
|
126
|
+
(parent: Answerable<PageElement>) =>
|
|
127
|
+
CssClasses.of(PageElement.of(pageElement, parent))
|
|
128
|
+
);
|
|
170
129
|
}
|
|
171
130
|
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import type { Answerable, AnswersQuestions,
|
|
1
|
+
import type { Answerable, AnswersQuestions, MetaQuestionAdapter, QuestionAdapter } from '@serenity-js/core';
|
|
2
2
|
import { d, Question } from '@serenity-js/core';
|
|
3
3
|
import { asyncMap } from '@serenity-js/core/lib/io';
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import type { PageElements } from '../models';
|
|
6
|
+
import { PageElement } from '../models';
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* Uses the {@apilink Actor|actor's} {@apilink Ability|ability} to {@apilink BrowseTheWeb} to retrieve
|
|
@@ -104,7 +105,15 @@ export class Text {
|
|
|
104
105
|
* @param pageElement
|
|
105
106
|
*/
|
|
106
107
|
static of(pageElement: QuestionAdapter<PageElement> | PageElement): MetaQuestionAdapter<PageElement, string> {
|
|
107
|
-
return
|
|
108
|
+
return Question.about(d`the text of ${ pageElement }`,
|
|
109
|
+
async actor => {
|
|
110
|
+
const element = await actor.answer(pageElement);
|
|
111
|
+
|
|
112
|
+
return element.text();
|
|
113
|
+
},
|
|
114
|
+
(parent: Answerable<PageElement>) =>
|
|
115
|
+
Text.of(PageElement.of(pageElement, parent))
|
|
116
|
+
);
|
|
108
117
|
}
|
|
109
118
|
|
|
110
119
|
/**
|
|
@@ -120,108 +129,21 @@ export class Text {
|
|
|
120
129
|
static ofAll(pageElements: PageElements): MetaQuestionAdapter<PageElement, string[]>
|
|
121
130
|
static ofAll(pageElements: Answerable<PageElement[]>): QuestionAdapter<string[]>
|
|
122
131
|
static ofAll(pageElements: PageElements | Answerable<PageElement[]>): QuestionAdapter<string[]> {
|
|
123
|
-
if (pageElements
|
|
124
|
-
return
|
|
132
|
+
if (Question.isAMetaQuestion(pageElements)) {
|
|
133
|
+
return Question.about(d`the text of ${ pageElements }`,
|
|
134
|
+
textOfMultiple(pageElements),
|
|
135
|
+
(parent: Answerable<PageElement>) =>
|
|
136
|
+
Text.ofAll(pageElements.of(parent))
|
|
137
|
+
);
|
|
125
138
|
}
|
|
126
139
|
|
|
127
|
-
return Question.about(d`the text of ${ pageElements }`,
|
|
128
|
-
const elements: PageElement[] = await actor.answer(pageElements);
|
|
129
|
-
|
|
130
|
-
return asyncMap(elements, element => element.text());
|
|
131
|
-
});
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
class TextOfSingleElement
|
|
136
|
-
extends Question<Promise<string>>
|
|
137
|
-
implements MetaQuestion<PageElement, string>
|
|
138
|
-
{
|
|
139
|
-
/**
|
|
140
|
-
* @private
|
|
141
|
-
*/
|
|
142
|
-
private subject: string;
|
|
143
|
-
|
|
144
|
-
static of(element: QuestionAdapter<PageElement> | PageElement): MetaQuestionAdapter<PageElement, string> {
|
|
145
|
-
return Question.createAdapter(new TextOfSingleElement(element)) as MetaQuestionAdapter<PageElement, string>;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
protected constructor(private readonly element: QuestionAdapter<PageElement> | PageElement) {
|
|
149
|
-
super();
|
|
150
|
-
this.subject = d`the text of ${ element }`;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
of(parent: QuestionAdapter<PageElement> | PageElement): Question<Promise<string>> {
|
|
154
|
-
return new TextOfSingleElement(PageElement.of(this.element, parent));
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
/**
|
|
158
|
-
* @inheritDoc
|
|
159
|
-
*/
|
|
160
|
-
async answeredBy(actor: AnswersQuestions & UsesAbilities): Promise<string> {
|
|
161
|
-
const element = await actor.answer(this.element);
|
|
162
|
-
|
|
163
|
-
return element.text();
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
/**
|
|
167
|
-
* @inheritDoc
|
|
168
|
-
*/
|
|
169
|
-
describedAs(subject: string): this {
|
|
170
|
-
this.subject = subject;
|
|
171
|
-
return this;
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
/**
|
|
175
|
-
* @inheritDoc
|
|
176
|
-
*/
|
|
177
|
-
toString(): string {
|
|
178
|
-
return this.subject;
|
|
140
|
+
return Question.about(d`the text of ${ pageElements }`, textOfMultiple(pageElements));
|
|
179
141
|
}
|
|
180
142
|
}
|
|
181
143
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
{
|
|
186
|
-
/**
|
|
187
|
-
* @private
|
|
188
|
-
*/
|
|
189
|
-
private subject: string;
|
|
190
|
-
|
|
191
|
-
static of(elements: PageElements): MetaQuestionAdapter<PageElement, string[]> {
|
|
192
|
-
return Question.createAdapter(new TextOfMultipleElements(elements)) as MetaQuestionAdapter<PageElement, string[]>;
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
protected constructor(private readonly elements: PageElements) {
|
|
196
|
-
super();
|
|
197
|
-
this.subject = d`the text of ${ elements }`;
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
of(parent: Answerable<PageElement>): Question<Promise<string[]>> {
|
|
201
|
-
return new TextOfMultipleElements(this.elements.of(parent));
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
/**
|
|
205
|
-
* @inheritDoc
|
|
206
|
-
*/
|
|
207
|
-
async answeredBy(actor: AnswersQuestions & UsesAbilities): Promise<string[]> {
|
|
208
|
-
const elements: PageElement[] = await actor.answer(this.elements);
|
|
209
|
-
|
|
144
|
+
function textOfMultiple(pageElements: Answerable<PageElement[]>) {
|
|
145
|
+
return async (actor: AnswersQuestions) => {
|
|
146
|
+
const elements: PageElement[] = await actor.answer(pageElements);
|
|
210
147
|
return asyncMap(elements, element => element.text());
|
|
211
148
|
}
|
|
212
|
-
|
|
213
|
-
/**
|
|
214
|
-
* @inheritDoc
|
|
215
|
-
*/
|
|
216
|
-
describedAs(subject: string): this {
|
|
217
|
-
this.subject = subject;
|
|
218
|
-
return this;
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
/**
|
|
222
|
-
* @inheritDoc
|
|
223
|
-
*/
|
|
224
|
-
toString(): string {
|
|
225
|
-
return this.subject;
|
|
226
|
-
}
|
|
227
149
|
}
|