@kogeet/sagent-playwright 0.1.0

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.
@@ -0,0 +1,61 @@
1
+ import type { Page } from "playwright";
2
+ import { chromium, firefox, webkit } from "playwright";
3
+ import type { BrowserContextOptions } from "playwright-core";
4
+ type Navigator = typeof chromium | typeof firefox | typeof webkit;
5
+ declare class CoreBrowser {
6
+ private browser;
7
+ private ctx;
8
+ private idxActivePage;
9
+ /**
10
+ * **Launch browser and retrieve appropriate context**
11
+ * @param navig chromium or firefox or webkit
12
+ * @param device kind of device (ex : iPhone11, Desktop Firefox, ...)
13
+ * @param channel required for some devices : chrome or firefox or msedge
14
+ */
15
+ createBrowser(navig: Navigator, device: BrowserContextOptions | undefined, channel?: string | undefined): Promise<void>;
16
+ /**
17
+ * **Create a new page and activate it**
18
+ */
19
+ createPage(): Promise<Page | undefined>;
20
+ /**
21
+ * **Return current active page**
22
+ *
23
+ * return 'undefined' if there is no active page
24
+ */
25
+ getActivePage(): Page | undefined;
26
+ /**
27
+ * **Return the handle of the current active page**
28
+ *
29
+ * The handle is a number converted to string
30
+ */
31
+ getCurrentPageHandle(): string;
32
+ /**
33
+ * **Switch to another existing page and activate it**
34
+ *
35
+ * Return false if handle does not match any page, otherwise return true.
36
+ * @param handle String that is a unique page identifier
37
+ */
38
+ switchToPage(handle: string): Promise<boolean>;
39
+ /**
40
+ * **Return a promise for a new page**
41
+ *
42
+ * To be used with ***switchToNewPage***
43
+ */
44
+ pagePromise(): Promise<Page> | undefined;
45
+ /**
46
+ * **Switch to a new page opened on another tab by a previous action**
47
+ * @param pagePromise the promise of new page
48
+ */
49
+ switchToNewPage(pagePromise: Promise<Page>): Promise<void>;
50
+ /**
51
+ * **Wait current active page to be loaded**
52
+ */
53
+ waitForLoadActivePage(): Promise<void>;
54
+ /**
55
+ * **Close browser**
56
+ */
57
+ close(): Promise<void>;
58
+ }
59
+ declare const core: CoreBrowser;
60
+ export default core;
61
+ //# sourceMappingURL=Core.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Core.d.ts","sourceRoot":"","sources":["../../src/core/Core.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAA0B,IAAI,EAAC,MAAM,YAAY,CAAC;AAC9D,OAAO,EAAC,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAC,MAAM,YAAY,CAAC;AACrD,OAAO,KAAK,EAAC,qBAAqB,EAAC,MAAM,iBAAiB,CAAC;AAE3D,KAAK,SAAS,GAAG,OAAO,QAAQ,GAAG,OAAO,OAAO,GAAG,OAAO,MAAM,CAAA;AAEjE,cAAM,WAAW;IACf,OAAO,CAAC,OAAO,CAAqB;IACpC,OAAO,CAAC,GAAG,CAA4B;IACvC,OAAO,CAAC,aAAa,CAAe;IAEpC;;;;;OAKG;IACU,aAAa,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,qBAAqB,GAAG,SAAS,EAAE,OAAO,GAAC,MAAM,GAAC,SAAqB;IAK5H;;OAEG;IACU,UAAU,IAAI,OAAO,CAAC,IAAI,GAAG,SAAS,CAAC;IAUpD;;;;OAIG;IACI,aAAa,IAAI,IAAI,GAAG,SAAS;IAOxC;;;;OAIG;IACI,oBAAoB;IAI3B;;;;;OAKG;IACU,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAY3D;;;;OAIG;IACI,WAAW;IAIlB;;;OAGG;IACU,eAAe,CAAC,WAAW,EAAE,OAAO,CAAC,IAAI,CAAC;IASvD;;OAEG;IACU,qBAAqB;IAOlC;;OAEG;IACU,KAAK;CAQnB;AAED,QAAA,MAAM,IAAI,aAAoB,CAAA;AAC9B,eAAe,IAAI,CAAA"}
@@ -0,0 +1,108 @@
1
+ import { chromium, firefox, webkit } from "playwright";
2
+ class CoreBrowser {
3
+ browser;
4
+ ctx;
5
+ idxActivePage = '-1';
6
+ /**
7
+ * **Launch browser and retrieve appropriate context**
8
+ * @param navig chromium or firefox or webkit
9
+ * @param device kind of device (ex : iPhone11, Desktop Firefox, ...)
10
+ * @param channel required for some devices : chrome or firefox or msedge
11
+ */
12
+ async createBrowser(navig, device, channel = undefined) {
13
+ this.browser = await navig.launch({ channel, headless: false });
14
+ this.ctx = await this.browser.newContext(device);
15
+ }
16
+ /**
17
+ * **Create a new page and activate it**
18
+ */
19
+ async createPage() {
20
+ if (this.ctx) {
21
+ const page = await this.ctx.newPage();
22
+ this.idxActivePage = (this.ctx.pages().length - 1).toString();
23
+ await page.bringToFront();
24
+ }
25
+ else {
26
+ return undefined;
27
+ }
28
+ }
29
+ /**
30
+ * **Return current active page**
31
+ *
32
+ * return 'undefined' if there is no active page
33
+ */
34
+ getActivePage() {
35
+ const idx = Number(this.idxActivePage);
36
+ if (this.ctx && idx > -1) {
37
+ return this.ctx.pages()[idx];
38
+ }
39
+ }
40
+ /**
41
+ * **Return the handle of the current active page**
42
+ *
43
+ * The handle is a number converted to string
44
+ */
45
+ getCurrentPageHandle() {
46
+ return this.idxActivePage;
47
+ }
48
+ /**
49
+ * **Switch to another existing page and activate it**
50
+ *
51
+ * Return false if handle does not match any page, otherwise return true.
52
+ * @param handle String that is a unique page identifier
53
+ */
54
+ async switchToPage(handle) {
55
+ const idx = Number(handle);
56
+ if (this.ctx && idx > -1 && idx <= this.ctx.pages().length) {
57
+ const page = this.ctx.pages()[idx];
58
+ await page.bringToFront();
59
+ this.idxActivePage = handle;
60
+ return true;
61
+ }
62
+ else {
63
+ return false;
64
+ }
65
+ }
66
+ /**
67
+ * **Return a promise for a new page**
68
+ *
69
+ * To be used with ***switchToNewPage***
70
+ */
71
+ pagePromise() {
72
+ return this.ctx ? this.ctx.waitForEvent('page') : undefined;
73
+ }
74
+ /**
75
+ * **Switch to a new page opened on another tab by a previous action**
76
+ * @param pagePromise the promise of new page
77
+ */
78
+ async switchToNewPage(pagePromise) {
79
+ const newPage = await pagePromise;
80
+ await newPage.waitForLoadState('load');
81
+ await newPage.bringToFront();
82
+ if (this.ctx) {
83
+ this.idxActivePage = (this.ctx.pages().length - 1).toString();
84
+ }
85
+ }
86
+ /**
87
+ * **Wait current active page to be loaded**
88
+ */
89
+ async waitForLoadActivePage() {
90
+ const page = this.getActivePage();
91
+ if (page) {
92
+ await page.waitForLoadState();
93
+ }
94
+ }
95
+ /**
96
+ * **Close browser**
97
+ */
98
+ async close() {
99
+ if (this.ctx) {
100
+ await this.ctx.close();
101
+ }
102
+ if (this.browser) {
103
+ await this.browser.close();
104
+ }
105
+ }
106
+ }
107
+ const core = new CoreBrowser();
108
+ export default core;
@@ -0,0 +1,4 @@
1
+ import type { StepContext } from "@kogeet/scapin-core-agent";
2
+ import type { Locator } from "playwright";
3
+ export default function uiWrapper(stepCtx: StepContext, callback: (stepCtx: StepContext, elem: Locator) => Promise<boolean>): Promise<boolean>;
4
+ //# sourceMappingURL=LocatorLib.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LocatorLib.d.ts","sourceRoot":"","sources":["../../src/core/LocatorLib.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAgB,WAAW,EAAC,MAAM,2BAA2B,CAAC;AAE1E,OAAO,KAAK,EAAe,OAAO,EAAC,MAAM,YAAY,CAAC;AAKtD,wBAA8B,SAAS,CAAC,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,CAAC,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,OAAO,KAAK,OAAO,CAAC,OAAO,CAAC,oBAchI"}
@@ -0,0 +1,135 @@
1
+ import { report } from "@kogeet/scapin-core-agent";
2
+ import core from "./Core.js";
3
+ export default async function uiWrapper(stepCtx, callback) {
4
+ const wl = new LocatorLib(stepCtx.getAllConfigs());
5
+ const elem = await wl.findLocator();
6
+ if (elem) {
7
+ if (await elem.count() > 1) {
8
+ report.warning('> Found more than one éléments. Take the first one');
9
+ }
10
+ return await callback(stepCtx, elem.first());
11
+ }
12
+ else {
13
+ report.warning('No elem found');
14
+ return false;
15
+ }
16
+ }
17
+ class LocatorLib {
18
+ configList;
19
+ locator = null;
20
+ frameLocator = null;
21
+ constructor(configList) {
22
+ this.configList = configList;
23
+ }
24
+ async findLocator() {
25
+ this.locator = null;
26
+ if (this.configList && this.configList.length) {
27
+ for (let idx = 0; idx < this.configList.length; idx++) {
28
+ const { key, value } = this.configList[idx];
29
+ let selector = null;
30
+ let supported_key = true;
31
+ switch (key) {
32
+ case 'id':
33
+ selector = `#${value}`;
34
+ break;
35
+ case 'selector':
36
+ case 'iframe':
37
+ selector = `${value}`;
38
+ break;
39
+ case 'class':
40
+ selector = `.${value}`;
41
+ break;
42
+ case 'rank':
43
+ await this.nthLocator(value);
44
+ break;
45
+ case 'name':
46
+ selector = `[name="${value}"]`;
47
+ break;
48
+ case 'role':
49
+ selector = `[role="${value}"]`;
50
+ break;
51
+ case 'exactText':
52
+ this.getByText(value, true);
53
+ break;
54
+ case 'partialText':
55
+ this.getByText(value, false);
56
+ break;
57
+ default:
58
+ console.log(`> Mapping ${key} not supported or deprecated`);
59
+ supported_key = false;
60
+ }
61
+ if (supported_key) {
62
+ this.getLocator(idx, selector);
63
+ await this.logLocator(key, value);
64
+ }
65
+ }
66
+ }
67
+ else {
68
+ // erreur de paramètre
69
+ report.info('Mapping parameters not found');
70
+ }
71
+ return this.locator;
72
+ }
73
+ getLocator(idx, selector) {
74
+ const page = core.getActivePage();
75
+ if (page) {
76
+ if (selector) {
77
+ if (idx === 0) {
78
+ this.locator = page.locator(selector);
79
+ }
80
+ else if (this.locator) {
81
+ this.locator = this.locator.locator(selector);
82
+ }
83
+ else if (this.frameLocator) {
84
+ this.locator = this.frameLocator.locator(selector);
85
+ this.frameLocator = null;
86
+ }
87
+ else {
88
+ // selector != null && idx > 0 && this.locator = null && this.frameLocator = null
89
+ report.info('No such element error');
90
+ }
91
+ }
92
+ }
93
+ else {
94
+ report.info('No browser available');
95
+ }
96
+ }
97
+ async logLocator(key, value) {
98
+ if (this.locator) {
99
+ try {
100
+ // Needed for Locator inside an iframe to be found
101
+ await this.locator.first().waitFor();
102
+ }
103
+ catch (e) {
104
+ console.log(`> [${key}: ${value}] wait for locator failed`);
105
+ await core.close();
106
+ throw new Error('LOCATOR_TIMEOUT');
107
+ }
108
+ const count = await this.locator.count();
109
+ console.log(`> [${key}: ${value}] found ${count} éléments`);
110
+ if (key === 'iframe') {
111
+ this.frameLocator = this.locator.first().frameLocator(':scope');
112
+ this.locator = null;
113
+ }
114
+ }
115
+ else {
116
+ console.log(`> [${key}: ${value}] found 0 éléments`);
117
+ }
118
+ }
119
+ async nthLocator(value) {
120
+ if (this.locator) {
121
+ const count = await this.locator.count();
122
+ let nth = +value - 1;
123
+ if (nth < 0)
124
+ nth = 0;
125
+ if (nth >= count)
126
+ nth = count - 1;
127
+ this.locator = this.locator.nth(nth);
128
+ }
129
+ }
130
+ getByText(value, exact) {
131
+ if (this.locator) {
132
+ this.locator = this.locator.getByText(value, { exact });
133
+ }
134
+ }
135
+ }
package/bin/index.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/bin/index.js ADDED
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env node
2
+ // La ligne ci-dessus est requise pour que la commande sagent-playwright fonctionne
3
+ // après installation du package en global
4
+ import { sagent } from "@kogeet/scapin-core-agent";
5
+ import * as fs from "fs";
6
+ import BrowserLib from "./libs/BrowserLib.js";
7
+ import StdLib from "./libs/StdLib.js";
8
+ import DatasetEntryPoints from "@kogeet/sagent-plugin-dataset";
9
+ const loadJSON = (path) => JSON.parse(fs.readFileSync(new URL(path, import.meta.url)).toString());
10
+ const pjson = loadJSON('../package.json');
11
+ // Librairies prises en charge
12
+ sagent.use('BrowserLib', BrowserLib.entryPoints);
13
+ sagent.use('StdLib', StdLib.entryPoints);
14
+ sagent.use('DatasetLib', DatasetEntryPoints);
15
+ console.log('Starting Scapin Playwright Agent version', pjson.version);
16
+ sagent.listen();
@@ -0,0 +1,19 @@
1
+ import { StepContext } from "@kogeet/scapin-core-agent";
2
+ export default class BrowserLib {
3
+ static entryPoints: Map<string, typeof BrowserLib.BrowserRunToURL>;
4
+ static BrowserRunToURL(stepCtx: StepContext): Promise<boolean>;
5
+ static BrowserQuit(): Promise<boolean>;
6
+ static BrowserGotoURL(stepCtx: StepContext): Promise<boolean>;
7
+ static BrowserBack(): Promise<boolean>;
8
+ static BrowserForward(): Promise<boolean>;
9
+ static BrowserGetTitle(stepCtx: StepContext): Promise<boolean>;
10
+ static BrowserHasTitle(stepCtx: StepContext): Promise<boolean>;
11
+ static BrowserRefresh(): Promise<boolean>;
12
+ static BrowserTabToUrl(stepCtx: StepContext): Promise<boolean>;
13
+ static BrowserWindowToUrl(stepCtx: StepContext): Promise<boolean>;
14
+ static BrowserSwitch(stepCtx: StepContext): Promise<boolean>;
15
+ static BrowserGetCurrentURL(stepCtx: StepContext): Promise<boolean>;
16
+ private static goToUrl;
17
+ private static browserToUrl;
18
+ }
19
+ //# sourceMappingURL=BrowserLib.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BrowserLib.d.ts","sourceRoot":"","sources":["../../src/libs/BrowserLib.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,WAAW,EAAC,MAAM,2BAA2B,CAAC;AAIvE,MAAM,CAAC,OAAO,OAAO,UAAU;IAE7B,OAAc,WAAW,iDAavB;WAEkB,eAAe,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC;WAsCvD,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;WAU/B,cAAc,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC;WAUtD,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;WAgB/B,cAAc,IAAI,OAAO,CAAC,OAAO,CAAC;WAgBlC,eAAe,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC;WAiBvD,eAAe,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC;WAiBvD,cAAc,IAAI,OAAO,CAAC,OAAO,CAAC;WAgBlC,eAAe,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC;WAQvD,kBAAkB,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC;WAM1D,aAAa,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC;WASrD,oBAAoB,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC;mBAiB3D,OAAO;mBAWP,YAAY;CAYlC"}
@@ -0,0 +1,220 @@
1
+ import { context, report, StepContext } from "@kogeet/scapin-core-agent";
2
+ import { chromium, devices, firefox } from "playwright";
3
+ import core from "../core/Core.js";
4
+ export default class BrowserLib {
5
+ static entryPoints = new Map([
6
+ ['browserRunToURL', BrowserLib.BrowserRunToURL],
7
+ ['browserQuit', BrowserLib.BrowserQuit],
8
+ ['browserGotoURL', BrowserLib.BrowserGotoURL],
9
+ ['browserBack', BrowserLib.BrowserBack],
10
+ ['browserForward', BrowserLib.BrowserForward],
11
+ ['browserGetTitle', BrowserLib.BrowserGetTitle],
12
+ ['browserHasTitle', BrowserLib.BrowserHasTitle],
13
+ ['browserRefresh', BrowserLib.BrowserRefresh],
14
+ ['browserWin2Url', BrowserLib.BrowserWindowToUrl],
15
+ ['browserTab2Url', BrowserLib.BrowserTabToUrl],
16
+ ['browserSwitch', BrowserLib.BrowserSwitch],
17
+ ['browserGetCurrentURL', BrowserLib.BrowserGetCurrentURL]
18
+ ]);
19
+ static async BrowserRunToURL(stepCtx) {
20
+ // Récupération des paramètres
21
+ const browserName = stepCtx.getStringParam('0');
22
+ const url = (stepCtx.getStringParam('1')).toLowerCase();
23
+ // Exécution
24
+ try {
25
+ switch (browserName) {
26
+ case 'chrome':
27
+ await core.createBrowser(chromium, { ...devices['Desktop Chrome'] }, 'chrome');
28
+ break;
29
+ case 'firefox':
30
+ await core.createBrowser(firefox, { ...devices['Desktop Firefox'] }, 'firefox');
31
+ break;
32
+ case 'msedge':
33
+ await core.createBrowser(chromium, { ...devices['Desktop Edge'] }, 'msedge');
34
+ break;
35
+ case 'pixel5':
36
+ await core.createBrowser(chromium, { ...devices['Pixel 5'] });
37
+ break;
38
+ case 'pixel5L':
39
+ await core.createBrowser(chromium, { ...devices['Pixel 5 landscape'] });
40
+ break;
41
+ default:
42
+ report.error(`LaunchToUrl value '${browserName}' is invalid for Browser parameter`);
43
+ return false;
44
+ }
45
+ await core.createPage();
46
+ context.setVariable(stepCtx.getStringParam('2'), core.getCurrentPageHandle());
47
+ return await BrowserLib.goToUrl(url, 'LaunchToUrl');
48
+ }
49
+ catch (e) {
50
+ report.error(`LaunchToUrl error for '${browserName}' : ${e.message}`);
51
+ return false;
52
+ }
53
+ }
54
+ static async BrowserQuit() {
55
+ try {
56
+ await core.close();
57
+ return true;
58
+ }
59
+ catch (e) {
60
+ report.error(`Quit browser error : ${e.message}`);
61
+ return false;
62
+ }
63
+ }
64
+ static async BrowserGotoURL(stepCtx) {
65
+ const url = stepCtx.getStringParam('0');
66
+ try {
67
+ return await BrowserLib.goToUrl(url, 'GoToUrl');
68
+ }
69
+ catch (e) {
70
+ report.error(`GoToUrl error : ${e.message}`);
71
+ return false;
72
+ }
73
+ }
74
+ static async BrowserBack() {
75
+ try {
76
+ const page = core.getActivePage();
77
+ if (page) {
78
+ await page.goBack();
79
+ return true;
80
+ }
81
+ else {
82
+ report.error(`Back unexpected error : There is no active page`);
83
+ return false;
84
+ }
85
+ }
86
+ catch (e) {
87
+ report.error(`Back error : ${e.message}`);
88
+ return false;
89
+ }
90
+ }
91
+ static async BrowserForward() {
92
+ try {
93
+ const page = core.getActivePage();
94
+ if (page) {
95
+ await page.goForward();
96
+ return true;
97
+ }
98
+ else {
99
+ report.error(`Forward unexpected error : There is no active page`);
100
+ return false;
101
+ }
102
+ }
103
+ catch (e) {
104
+ report.error(`Forward error : ${e.message}`);
105
+ return false;
106
+ }
107
+ }
108
+ static async BrowserGetTitle(stepCtx) {
109
+ try {
110
+ const page = core.getActivePage();
111
+ if (page) {
112
+ const title = await page.title();
113
+ context.setVariable(stepCtx.getStringParam('0'), title);
114
+ return true;
115
+ }
116
+ else {
117
+ report.error(`GetTitle unexpected error : There is no active page`);
118
+ return false;
119
+ }
120
+ }
121
+ catch (e) {
122
+ report.error(`GetTitle error : ${e.message}`);
123
+ return false;
124
+ }
125
+ }
126
+ static async BrowserHasTitle(stepCtx) {
127
+ try {
128
+ const page = core.getActivePage();
129
+ if (page) {
130
+ const title = await page.title();
131
+ return stepCtx.getStringParam('0') === title;
132
+ }
133
+ else {
134
+ report.error(`HasTitle unexpected error : There is no active page`);
135
+ return false;
136
+ }
137
+ }
138
+ catch (e) {
139
+ report.error(`HasTitle error : ${e.message}`);
140
+ return false;
141
+ }
142
+ }
143
+ static async BrowserRefresh() {
144
+ try {
145
+ const page = core.getActivePage();
146
+ if (page) {
147
+ await page.reload();
148
+ return true;
149
+ }
150
+ else {
151
+ report.error(`Refresh unexpected error : There is no active page`);
152
+ return false;
153
+ }
154
+ }
155
+ catch (e) {
156
+ report.error(`Refresh error : ${e.message}`);
157
+ return false;
158
+ }
159
+ }
160
+ static async BrowserTabToUrl(stepCtx) {
161
+ const url = stepCtx.getStringParam('0');
162
+ const varName = stepCtx.getStringParam('1');
163
+ return await BrowserLib.browserToUrl(url, varName, 'OpenTabToUrl');
164
+ }
165
+ // 'BrowserWindowToUrl' est maintenu pour des raisons de compatibilité avec Selenium
166
+ // mais fait la même chose que 'BrowserTabToUrl'
167
+ static async BrowserWindowToUrl(stepCtx) {
168
+ const url = stepCtx.getStringParam('0');
169
+ const varName = stepCtx.getStringParam('1');
170
+ return await BrowserLib.browserToUrl(url, varName, 'OpenWindowToUrl');
171
+ }
172
+ static async BrowserSwitch(stepCtx) {
173
+ try {
174
+ return core.switchToPage(stepCtx.getStringParam('0'));
175
+ }
176
+ catch (e) {
177
+ report.error(`SwitchTo error : ${e.message}`);
178
+ return false;
179
+ }
180
+ }
181
+ static async BrowserGetCurrentURL(stepCtx) {
182
+ try {
183
+ const page = core.getActivePage();
184
+ if (page) {
185
+ context.setVariable(stepCtx.getStringParam('0'), page.url());
186
+ return true;
187
+ }
188
+ else {
189
+ report.error(`GetTabUrl unexpected error : There is no active page`);
190
+ return false;
191
+ }
192
+ }
193
+ catch (e) {
194
+ report.error(`GetTabUrl error : ${e.message}`);
195
+ return false;
196
+ }
197
+ }
198
+ static async goToUrl(url, fromMsg = '') {
199
+ const page = core.getActivePage();
200
+ if (page) {
201
+ await page.goto(url);
202
+ return true;
203
+ }
204
+ else {
205
+ report.error(`${fromMsg} unexpected error : There is no active page`);
206
+ return false;
207
+ }
208
+ }
209
+ static async browserToUrl(url, varName, fromMsg) {
210
+ try {
211
+ await core.createPage();
212
+ context.setVariable(varName, core.getCurrentPageHandle());
213
+ return await BrowserLib.goToUrl(url, fromMsg);
214
+ }
215
+ catch (e) {
216
+ report.error(`${fromMsg} error : ${e.message}`);
217
+ return false;
218
+ }
219
+ }
220
+ }
@@ -0,0 +1,75 @@
1
+ import type { StepContext } from "@kogeet/scapin-core-agent";
2
+ export default class StdLib {
3
+ static entryPoints: Map<string, typeof StdLib.elemClick>;
4
+ /**
5
+ * **Implémentation de l'instruction d'action Click**
6
+ * @param stepCtx Paramètre du step
7
+ */
8
+ static elemClick(stepCtx: StepContext): Promise<boolean>;
9
+ /**
10
+ * **Implémentation de l'instruction d'action InputText**
11
+ * @param stepCtx Paramètre du step
12
+ */
13
+ static elemSetText(stepCtx: StepContext): Promise<boolean>;
14
+ /**
15
+ * **Implémentation de l'instruction d'action GetText**
16
+ *
17
+ * Retrieve the text of an element
18
+ * @param stepCtx Paramètre du step
19
+ */
20
+ static elemGetText(stepCtx: StepContext): Promise<boolean>;
21
+ /**
22
+ * **Implémentation de l'instruction de contrôle HasText**
23
+ *
24
+ * Renvoie *true* si le texte passé en paramètre est celui de l'élément
25
+ * @param stepCtx Paramètre du step
26
+ */
27
+ static elemHasText(stepCtx: StepContext): Promise<boolean>;
28
+ /**
29
+ * **Implémentation de l'instruction de contrôle IsVisible**
30
+ * @param stepCtx Paramètre du step
31
+ */
32
+ static elemIsVisible(stepCtx: StepContext): Promise<boolean>;
33
+ /**
34
+ * **Implémentation de l'instruction de contrôle IsEnabled**
35
+ * @param stepCtx Paramètre du step
36
+ */
37
+ static elemIsEnabled(stepCtx: StepContext): Promise<boolean>;
38
+ /**
39
+ * **Implémentation de l'instruction de contrôle HasState**
40
+ *
41
+ * Contrôle l'état coché ou non d'une checkbox ou d'un radio-bouton
42
+ * @param stepCtx Paramètre du step
43
+ */
44
+ static elemHasState(stepCtx: StepContext): Promise<boolean>;
45
+ /**
46
+ * **Implémentation de l'instruction d'action GetState**
47
+ *
48
+ * Récupère l'état coché ou décoché d'une checkbox ou d'un radio-bouton
49
+ * @param stepCtx Paramètre du step
50
+ */
51
+ static elemGetState(stepCtx: StepContext): Promise<boolean>;
52
+ /**
53
+ * **Implémentation de l'instruction d'action setState**
54
+ *
55
+ * Coche ou décoche une checkbox ou un radio-bouton
56
+ * @param stepCtx Paramètre du step
57
+ */
58
+ static elemSetState(stepCtx: StepContext): Promise<boolean>;
59
+ /**
60
+ * **Implémentation de l'instruction d'action ClickAndOpen**
61
+ * @param stepCtx Paramètre du step
62
+ */
63
+ static elemClickToNew(stepCtx: StepContext): Promise<boolean>;
64
+ /**
65
+ * **Implémentation de l'instruction d'action setTimer**
66
+ * @param stepCtx Paramètre du step
67
+ */
68
+ static wait(stepCtx: StepContext): Promise<boolean>;
69
+ /**
70
+ * **Implémentation de l'instruction d'action Calculator**
71
+ * @param stepCtx Paramètre du step
72
+ */
73
+ static calculator(stepCtx: StepContext): Promise<boolean>;
74
+ }
75
+ //# sourceMappingURL=StdLib.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StdLib.d.ts","sourceRoot":"","sources":["../../src/libs/StdLib.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,2BAA2B,CAAC;AAM3D,MAAM,CAAC,OAAO,OAAO,MAAM;IAEzB,OAAc,WAAW,uCAavB;IAEF;;;OAGG;WACiB,SAAS,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC;IAarE;;;OAGG;WACiB,WAAW,CAAC,OAAO,EAAE,WAAW;IAiBpD;;;;;OAKG;WACiB,WAAW,CAAC,OAAO,EAAE,WAAW;IAapD;;;;;OAKG;WACiB,WAAW,CAAC,OAAO,EAAE,WAAW;IAqBpD;;;OAGG;WACiB,aAAa,CAAC,OAAO,EAAE,WAAW;IAYtD;;;OAGG;WACiB,aAAa,CAAC,OAAO,EAAE,WAAW;IAYtD;;;;;OAKG;WACiB,YAAY,CAAC,OAAO,EAAE,WAAW;IAarD;;;;;OAKG;WACiB,YAAY,CAAC,OAAO,EAAE,WAAW;IAYrD;;;;;OAKG;WACiB,YAAY,CAAC,OAAO,EAAE,WAAW;IAgBrD;;;OAGG;WACiB,cAAc,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC;IAiB1E;;;OAGG;WACiB,IAAI,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC;IAMhE;;;OAGG;WACiB,UAAU,CAAC,OAAO,EAAE,WAAW;CAkCpD"}
@@ -0,0 +1,234 @@
1
+ import uiWrapper from "../core/LocatorLib.js";
2
+ import { context, report } from "@kogeet/scapin-core-agent";
3
+ import core from "../core/Core.js";
4
+ export default class StdLib {
5
+ static entryPoints = new Map([
6
+ ['elemClick', StdLib.elemClick],
7
+ ['elemSetText', StdLib.elemSetText],
8
+ ['elemGetText', StdLib.elemGetText],
9
+ ['elemHasText', StdLib.elemHasText],
10
+ ['elemIsVisible', StdLib.elemIsVisible],
11
+ ['elemIsEnabled', StdLib.elemIsEnabled],
12
+ ['elemHasState', StdLib.elemHasState],
13
+ ['elemGetState', StdLib.elemGetState],
14
+ ['elemSetState', StdLib.elemSetState],
15
+ ['elemClickToNew', StdLib.elemClickToNew],
16
+ ['wait', StdLib.wait],
17
+ ['calculator', StdLib.calculator]
18
+ ]);
19
+ /**
20
+ * **Implémentation de l'instruction d'action Click**
21
+ * @param stepCtx Paramètre du step
22
+ */
23
+ static async elemClick(stepCtx) {
24
+ return await uiWrapper(stepCtx, async (stepCtx, elem) => {
25
+ try {
26
+ await elem.click();
27
+ await core.waitForLoadActivePage();
28
+ return true;
29
+ }
30
+ catch (e) {
31
+ report.warning(`Paywright error on 'Click' instruction : ${e.message}`);
32
+ return false;
33
+ }
34
+ });
35
+ }
36
+ /**
37
+ * **Implémentation de l'instruction d'action InputText**
38
+ * @param stepCtx Paramètre du step
39
+ */
40
+ static async elemSetText(stepCtx) {
41
+ const text = stepCtx.getStringParam('0', '');
42
+ // const clickBefore = stepCtx.getParam('1', true) Obsolète avec Playwright
43
+ // const eraseBefore = stepCtx.getParam('2', false) Obsolète avec Playwright
44
+ return await uiWrapper(stepCtx, async (stepCtx, elem) => {
45
+ try {
46
+ await elem.fill(text);
47
+ return true;
48
+ }
49
+ catch (e) {
50
+ report.warning(`Paywright error on 'InputText' instruction : ${e.message}`);
51
+ return false;
52
+ }
53
+ });
54
+ }
55
+ /**
56
+ * **Implémentation de l'instruction d'action GetText**
57
+ *
58
+ * Retrieve the text of an element
59
+ * @param stepCtx Paramètre du step
60
+ */
61
+ static async elemGetText(stepCtx) {
62
+ return await uiWrapper(stepCtx, async (stepCtx, elem) => {
63
+ try {
64
+ const text = await elem.innerText();
65
+ context.setVariable(stepCtx.getStringParam('0'), text);
66
+ return true;
67
+ }
68
+ catch (e) {
69
+ report.warning(`Paywright error on 'GetText' instruction : ${e.message}`);
70
+ return false;
71
+ }
72
+ });
73
+ }
74
+ /**
75
+ * **Implémentation de l'instruction de contrôle HasText**
76
+ *
77
+ * Renvoie *true* si le texte passé en paramètre est celui de l'élément
78
+ * @param stepCtx Paramètre du step
79
+ */
80
+ static async elemHasText(stepCtx) {
81
+ return await uiWrapper(stepCtx, async (stepCtx, elem) => {
82
+ try {
83
+ const text = await elem.innerText();
84
+ let pattern = stepCtx.getStringParam('0');
85
+ if (stepCtx.getParam('1', false) === true) {
86
+ pattern = `^${pattern}$`;
87
+ }
88
+ const regex = new RegExp(pattern);
89
+ const found = text.match(regex);
90
+ return !!found;
91
+ }
92
+ catch (e) {
93
+ report.warning(`Paywright error on 'HasText' instruction : ${e.message}`);
94
+ return false;
95
+ }
96
+ });
97
+ }
98
+ /**
99
+ * **Implémentation de l'instruction de contrôle IsVisible**
100
+ * @param stepCtx Paramètre du step
101
+ */
102
+ static async elemIsVisible(stepCtx) {
103
+ return await uiWrapper(stepCtx, async (stepCtx, elem) => {
104
+ try {
105
+ const elemVisible = await elem.isVisible();
106
+ return elemVisible === stepCtx.getParam('0', true);
107
+ }
108
+ catch (e) {
109
+ report.warning(`Paywright error on 'IsVisible' instruction : ${e.message}`);
110
+ return false;
111
+ }
112
+ });
113
+ }
114
+ /**
115
+ * **Implémentation de l'instruction de contrôle IsEnabled**
116
+ * @param stepCtx Paramètre du step
117
+ */
118
+ static async elemIsEnabled(stepCtx) {
119
+ return await uiWrapper(stepCtx, async (stepCtx, elem) => {
120
+ try {
121
+ const elemEnabled = await elem.isEnabled();
122
+ return elemEnabled === stepCtx.getParam('0', true);
123
+ }
124
+ catch (e) {
125
+ report.warning(`Paywright error on 'IsEnabled' instruction : ${e.message}`);
126
+ return false;
127
+ }
128
+ });
129
+ }
130
+ /**
131
+ * **Implémentation de l'instruction de contrôle HasState**
132
+ *
133
+ * Contrôle l'état coché ou non d'une checkbox ou d'un radio-bouton
134
+ * @param stepCtx Paramètre du step
135
+ */
136
+ static async elemHasState(stepCtx) {
137
+ return await uiWrapper(stepCtx, async (stepCtx, elem) => {
138
+ try {
139
+ const state = await elem.isChecked();
140
+ return state === stepCtx.getParam('0', true);
141
+ }
142
+ catch (e) {
143
+ report.warning(`Paywright error on 'HasState' instruction : ${e.message}`);
144
+ return false;
145
+ }
146
+ });
147
+ }
148
+ /**
149
+ * **Implémentation de l'instruction d'action GetState**
150
+ *
151
+ * Récupère l'état coché ou décoché d'une checkbox ou d'un radio-bouton
152
+ * @param stepCtx Paramètre du step
153
+ */
154
+ static async elemGetState(stepCtx) {
155
+ return await uiWrapper(stepCtx, async (stepCtx, elem) => {
156
+ try {
157
+ context.setVariable(stepCtx.getStringParam('0'), await elem.isChecked());
158
+ return true;
159
+ }
160
+ catch (e) {
161
+ report.warning(`Paywright error on 'GetState' instruction : ${e.message}`);
162
+ return false;
163
+ }
164
+ });
165
+ }
166
+ /**
167
+ * **Implémentation de l'instruction d'action setState**
168
+ *
169
+ * Coche ou décoche une checkbox ou un radio-bouton
170
+ * @param stepCtx Paramètre du step
171
+ */
172
+ static async elemSetState(stepCtx) {
173
+ return await uiWrapper(stepCtx, async (stepCtx, elem) => {
174
+ try {
175
+ if (stepCtx.getParam('0', true)) {
176
+ await elem.check();
177
+ }
178
+ else {
179
+ await elem.uncheck();
180
+ }
181
+ return true;
182
+ }
183
+ catch (e) {
184
+ report.warning(`Paywright error on 'SetState' instruction : ${e.message}`);
185
+ return false;
186
+ }
187
+ });
188
+ }
189
+ /**
190
+ * **Implémentation de l'instruction d'action ClickAndOpen**
191
+ * @param stepCtx Paramètre du step
192
+ */
193
+ static async elemClickToNew(stepCtx) {
194
+ return await uiWrapper(stepCtx, async (stepCtx, elem) => {
195
+ try {
196
+ const pagePromise = core.pagePromise();
197
+ if (pagePromise) {
198
+ await elem.click();
199
+ await core.switchToNewPage(pagePromise);
200
+ context.setVariable(stepCtx.getStringParam('0'), core.getCurrentPageHandle());
201
+ }
202
+ return true;
203
+ }
204
+ catch (e) {
205
+ report.warning(`Paywright error on 'ClickAndOpen' instruction : ${e.message}`);
206
+ return false;
207
+ }
208
+ });
209
+ }
210
+ /**
211
+ * **Implémentation de l'instruction d'action setTimer**
212
+ * @param stepCtx Paramètre du step
213
+ */
214
+ static async wait(stepCtx) {
215
+ const t = stepCtx.getParam('0', stepCtx.getConfig('0', 0));
216
+ await delay(t);
217
+ return true;
218
+ }
219
+ /**
220
+ * **Implémentation de l'instruction d'action Calculator**
221
+ * @param stepCtx Paramètre du step
222
+ */
223
+ static async calculator(stepCtx) {
224
+ context.setVariable(stepCtx.getStringParam('1'), stepCtx.getParam('0'));
225
+ return true;
226
+ }
227
+ }
228
+ function delay(t) {
229
+ return new Promise((done) => {
230
+ setTimeout(() => {
231
+ done();
232
+ }, t);
233
+ });
234
+ }
package/package.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "@kogeet/sagent-playwright",
3
+ "version": "0.1.0",
4
+ "description": "Scapin Agent for Playwright",
5
+ "main": "bin/index.js",
6
+ "publishConfig": {
7
+ "access": "public"
8
+ },
9
+ "engines": {
10
+ "node": "^18.17.1"
11
+ },
12
+ "scripts": {
13
+ "build": "tsc --sourceMap false --declaration true",
14
+ "termprod": "npm run build && node bin/index.js",
15
+ "np": "np --no-tests --message=sagent-playwright-%s"
16
+ },
17
+ "author": "Loïc Griveau",
18
+ "license": "MIT",
19
+ "dependencies": {
20
+ "@kogeet/sagent-plugin-dataset": "^0.1.1",
21
+ "@kogeet/scapin-core-agent": "^0.1.5",
22
+ "@playwright/browser-chromium": "^1.39.0",
23
+ "@playwright/browser-firefox": "^1.39.0",
24
+ "@playwright/browser-webkit": "^1.39.0",
25
+ "playwright": "^1.39.0"
26
+ },
27
+ "devDependencies": {
28
+ "@types/node": "^20.8.10",
29
+ "@typescript-eslint/eslint-plugin": "^6.8.0",
30
+ "@typescript-eslint/parser": "^6.8.0",
31
+ "eslint": "^8.51.0",
32
+ "typescript": "^5.2.2"
33
+ },
34
+ "type": "module",
35
+ "bin": {
36
+ "sagent-playwright": "bin/index.js"
37
+ }
38
+ }