new(basic.gblib): WEb Automation HOVER and LINK BY TEXT keywords.
This commit is contained in:
parent
ee5b9a7567
commit
f5826e1f0d
5 changed files with 127 additions and 42 deletions
1
gbot.sh
Executable file
1
gbot.sh
Executable file
|
@ -0,0 +1 @@
|
||||||
|
node .
|
|
@ -86,7 +86,7 @@ export class DialogKeywords {
|
||||||
hrOn: string;
|
hrOn: string;
|
||||||
|
|
||||||
step: GBDialogStep;
|
step: GBDialogStep;
|
||||||
|
|
||||||
public async getDeployer() {
|
public async getDeployer() {
|
||||||
return this.min.deployService;
|
return this.min.deployService;
|
||||||
}
|
}
|
||||||
|
@ -124,8 +124,8 @@ export class DialogKeywords {
|
||||||
*
|
*
|
||||||
* @example x = GET PAGE
|
* @example x = GET PAGE
|
||||||
*/
|
*/
|
||||||
public async getPage(step, url) {
|
public async getPage(step, url, username, password) {
|
||||||
|
GBLog.info(`BASIC: Web Automation GET PAGE ${url}.`);
|
||||||
if (!this.browser) {
|
if (!this.browser) {
|
||||||
this.browser = await puppeteer.launch({
|
this.browser = await puppeteer.launch({
|
||||||
args: [
|
args: [
|
||||||
|
@ -138,8 +138,14 @@ export class DialogKeywords {
|
||||||
ignoreHTTPSErrors: true,
|
ignoreHTTPSErrors: true,
|
||||||
headless: false,
|
headless: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// set the HTTP Basic Authentication credential
|
||||||
|
|
||||||
}
|
}
|
||||||
const page = await this.browser.newPage();
|
const page = await this.browser.newPage();
|
||||||
|
if (username || password) {
|
||||||
|
await page.authenticate({ 'username': username, 'password': password });
|
||||||
|
}
|
||||||
await page.goto(url);
|
await page.goto(url);
|
||||||
return page;
|
return page;
|
||||||
}
|
}
|
||||||
|
@ -237,12 +243,24 @@ export class DialogKeywords {
|
||||||
/**
|
/**
|
||||||
* Find element on page DOM.
|
* Find element on page DOM.
|
||||||
*
|
*
|
||||||
* @example GET page, "elementName", "text"
|
* @example GET page, "elementName"
|
||||||
*/
|
*/
|
||||||
public async getBySelector(page, elementName) {
|
public async getBySelector(page, elementName) {
|
||||||
|
GBLog.info(`BASIC: Web Automation GET element: ${elementName}.`);
|
||||||
await page.waitForSelector(elementName)
|
await page.waitForSelector(elementName)
|
||||||
let element = await page.$(elementName);
|
let elements = await page.$$(elementName);
|
||||||
return element;
|
if (elements && elements.length > 1) {
|
||||||
|
return elements;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const el = elements[0];
|
||||||
|
el['originalSelector'] = elementName;
|
||||||
|
el['href'] = await page.evaluate(e => e.getAttribute('href'), el);
|
||||||
|
el['value'] = await page.evaluate(e => e.getAttribute('value'), el);
|
||||||
|
el['name'] = await page.evaluate(e => e.getAttribute('name'), el);
|
||||||
|
el['class'] = await page.evaluate(e => e.getAttribute('class'), el);
|
||||||
|
return el;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -251,31 +269,59 @@ export class DialogKeywords {
|
||||||
* @example GET page, "frameSelector, "elementSelector"
|
* @example GET page, "frameSelector, "elementSelector"
|
||||||
*/
|
*/
|
||||||
public async getByFrame(page, frame, selector) {
|
public async getByFrame(page, frame, selector) {
|
||||||
|
GBLog.info(`BASIC: Web Automation GET element by frame: ${selector}.`);
|
||||||
await page.waitForSelector(frame)
|
await page.waitForSelector(frame)
|
||||||
let frameHandle = await page.$(frame);
|
let frameHandle = await page.$(frame);
|
||||||
const f = await frameHandle.contentFrame();
|
const f = await frameHandle.contentFrame();
|
||||||
await f.waitForSelector(selector);
|
await f.waitForSelector(selector);
|
||||||
const element = await f.$(selector);
|
const element = await f.$(selector);
|
||||||
element['originalSelector'] = selector;
|
element['originalSelector'] = selector;
|
||||||
|
element['href'] = await f.evaluate(e => e.getAttribute('href'), element);
|
||||||
|
element['value'] = await f.evaluate(e => e.getAttribute('value'), element);
|
||||||
|
element['name'] = await f.evaluate(e => e.getAttribute('name'), element);
|
||||||
|
element['class'] = await f.evaluate(e => e.getAttribute('class'), element);
|
||||||
element['frame'] = f;
|
element['frame'] = f;
|
||||||
return element;
|
return element;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the today data filled in dd/mm/yyyy or mm/dd/yyyy.
|
* Simulates a mouse hover an web page element.
|
||||||
|
*/
|
||||||
|
public async hover(step, page, idOrName) {
|
||||||
|
GBLog.info(`BASIC: Web Automation HOVER element: ${idOrName}.`);
|
||||||
|
await this.getBySelector(page, idOrName);
|
||||||
|
await page.hover(idOrName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clicks on an element in a web page.
|
||||||
*
|
*
|
||||||
* @example x = TODAY
|
* @example x = TODAY
|
||||||
*/
|
*/
|
||||||
public async click(step, page, idOrName) {
|
public async click(step, page, frameOrSelector, selector) {
|
||||||
const e = await this.getBySelector(page, idOrName);
|
GBLog.info(`BASIC: Web Automation CLICK element: ${frameOrSelector}.`);
|
||||||
|
if (selector) {
|
||||||
await Promise.all([
|
await page.waitForSelector(frameOrSelector)
|
||||||
page.waitForNavigation(),
|
let frameHandle = await page.$(frameOrSelector);
|
||||||
page.click(e.name)
|
const f = await frameHandle.contentFrame();
|
||||||
]);
|
await f.waitForSelector(selector);
|
||||||
|
await f.click(selector);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
await page.waitForSelector(frameOrSelector);
|
||||||
|
await page.click(frameOrSelector);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public async linkByText(step, page, text, index) {
|
||||||
|
GBLog.info(`BASIC: Web Automation CLICK LINK TEXT: ${text} ${index}.`);
|
||||||
|
if (!index) {
|
||||||
|
index = 1
|
||||||
|
}
|
||||||
|
const els = await page.$x(`//a[contains(., '${text}')]`);
|
||||||
|
await els[index - 1].click();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -285,6 +331,7 @@ export class DialogKeywords {
|
||||||
* @example file = SCREENSHOT page
|
* @example file = SCREENSHOT page
|
||||||
*/
|
*/
|
||||||
public async screenshot(step, page, idOrName, localName) {
|
public async screenshot(step, page, idOrName, localName) {
|
||||||
|
GBLog.info(`BASIC: Web Automation SCREENSHOT ${idOrName}.`);
|
||||||
const e = await this.getBySelector(page, idOrName);
|
const e = await this.getBySelector(page, idOrName);
|
||||||
await e.screenshot({ path: localName });
|
await e.screenshot({ path: localName });
|
||||||
}
|
}
|
||||||
|
@ -296,8 +343,9 @@ export class DialogKeywords {
|
||||||
* @example TYPE page, "elementName", "text"
|
* @example TYPE page, "elementName", "text"
|
||||||
*/
|
*/
|
||||||
public async type(step, page, idOrName, text) {
|
public async type(step, page, idOrName, text) {
|
||||||
|
GBLog.info(`BASIC: Web Automation TYPE on ${idOrName}: ${text}.`);
|
||||||
const e = await this.getBySelector(page, idOrName);
|
const e = await this.getBySelector(page, idOrName);
|
||||||
await e.type(text);
|
await e.type(text, { delay: 200 });
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -306,6 +354,7 @@ export class DialogKeywords {
|
||||||
* @example x = TODAY
|
* @example x = TODAY
|
||||||
*/
|
*/
|
||||||
public async getOCR(step, localFile) {
|
public async getOCR(step, localFile) {
|
||||||
|
GBLog.info(`BASIC: OCR processing on ${localFile}.`);
|
||||||
const tesseract = require("node-tesseract-ocr")
|
const tesseract = require("node-tesseract-ocr")
|
||||||
|
|
||||||
const config = {
|
const config = {
|
||||||
|
@ -407,12 +456,11 @@ export class DialogKeywords {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public getCoded(value){
|
public getCoded(value) {
|
||||||
|
|
||||||
// Checks if it is a GB FILE object.
|
// Checks if it is a GB FILE object.
|
||||||
|
|
||||||
if (value.data && value.filename)
|
if (value.data && value.filename) {
|
||||||
{
|
|
||||||
value = value.data;
|
value = value.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -687,6 +735,21 @@ export class DialogKeywords {
|
||||||
this.user = user;
|
this.user = user;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines the maximum lines to scan in spreedsheets.
|
||||||
|
*
|
||||||
|
* @example SET MAX COLUMNS 5000
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public async setMaxColumns(step, count) {
|
||||||
|
const user = await this.min.userProfile.get(step.context, {});
|
||||||
|
user.basicOptions.maxColumns = count;
|
||||||
|
await this.min.userProfile.set(step.context, user);
|
||||||
|
this.user = user;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Defines the FIND behaviour to consider whole words while searching.
|
* Defines the FIND behaviour to consider whole words while searching.
|
||||||
*
|
*
|
||||||
|
|
|
@ -324,41 +324,41 @@ export class GBVMService extends GBService {
|
||||||
});
|
});
|
||||||
|
|
||||||
code = code.replace(/(\w+)\s*\=\s*get\s(.*)/gi, ($0, $1, $2, $3) => {
|
code = code.replace(/(\w+)\s*\=\s*get\s(.*)/gi, ($0, $1, $2, $3) => {
|
||||||
|
|
||||||
const count = ($2.match(/\,/g) || []).length;
|
|
||||||
const values = $2.split(',');
|
|
||||||
|
|
||||||
// Handles GET page, "selector".
|
const count = ($2.match(/\,/g) || []).length;
|
||||||
|
const values = $2.split(',');
|
||||||
|
|
||||||
if (count == 1) {
|
// Handles GET page, "selector".
|
||||||
|
|
||||||
return `${$1} = this.getByIDOrName(${values[0]}, ${values[1]} )`;
|
if (count == 1) {
|
||||||
}
|
|
||||||
|
|
||||||
// Handles GET page, "frameSelector", "selector"
|
return `${$1} = this.getBySelector(${values[0]}, ${values[1]} )`;
|
||||||
|
}
|
||||||
|
|
||||||
else if (count == 2) {
|
// Handles GET page, "frameSelector", "selector"
|
||||||
|
|
||||||
return `${$1} = this.getByFrame(${values[0]}, ${values[1]}, ${values[2]} )`;
|
else if (count == 2) {
|
||||||
}
|
|
||||||
|
|
||||||
// Handles the GET http version.
|
return `${$1} = this.getByFrame(${values[0]}, ${values[1]}, ${values[2]} )`;
|
||||||
|
}
|
||||||
|
|
||||||
else {
|
// Handles the GET http version.
|
||||||
|
|
||||||
|
else {
|
||||||
|
|
||||||
|
return `${$1} = sys().get (${$2}, headers)`;
|
||||||
|
}
|
||||||
|
|
||||||
return `${$1} = sys().get (${$2}, headers)`;
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
code = code.replace(/\= NEW OBJECT/gi, ($0, $1, $2, $3) => {
|
code = code.replace(/\= NEW OBJECT/gi, ($0, $1, $2, $3) => {
|
||||||
return ` = {}`;
|
return ` = {}`;
|
||||||
});
|
});
|
||||||
|
|
||||||
code = code.replace(/\= NEW ARRAY/gi, ($0, $1, $2, $3) => {
|
code = code.replace(/\= NEW ARRAY/gi, ($0, $1, $2, $3) => {
|
||||||
return ` = []`;
|
return ` = []`;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
code = code.replace(/(go to)(\s)(.*)/gi, ($0, $1, $2, $3) => {
|
code = code.replace(/(go to)(\s)(.*)/gi, ($0, $1, $2, $3) => {
|
||||||
return `gotoDialog(step, ${$3})\n`;
|
return `gotoDialog(step, ${$3})\n`;
|
||||||
|
@ -392,6 +392,10 @@ export class GBVMService extends GBService {
|
||||||
return `setMaxLines (step, ${$3})\n`;
|
return `setMaxLines (step, ${$3})\n`;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
code = code.replace(/(set max columns)(\s*)(.*)/gi, ($0, $1, $2, $3) => {
|
||||||
|
return `setMaxColumns (step, ${$3})\n`;
|
||||||
|
});
|
||||||
|
|
||||||
code = code.replace(/(set translator)(\s*)(.*)/gi, ($0, $1, $2, $3) => {
|
code = code.replace(/(set translator)(\s*)(.*)/gi, ($0, $1, $2, $3) => {
|
||||||
return `setTranslatorOn (step, "${$3.toLowerCase()}")\n`;
|
return `setTranslatorOn (step, "${$3.toLowerCase()}")\n`;
|
||||||
});
|
});
|
||||||
|
@ -467,11 +471,19 @@ export class GBVMService extends GBService {
|
||||||
code = code.replace(/(send mail)(\s*)(.*)/gi, ($0, $1, $2, $3) => {
|
code = code.replace(/(send mail)(\s*)(.*)/gi, ($0, $1, $2, $3) => {
|
||||||
return `sendEmail (${$3})\n`;
|
return `sendEmail (${$3})\n`;
|
||||||
});
|
});
|
||||||
|
|
||||||
code = code.replace(/(send file to)(\s*)(.*)/gi, ($0, $1, $2, $3) => {
|
code = code.replace(/(send file to)(\s*)(.*)/gi, ($0, $1, $2, $3) => {
|
||||||
return `sendFileTo (step, ${$3})\n`;
|
return `sendFileTo (step, ${$3})\n`;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
code = code.replace(/(hover)(\s*)(.*)/gi, ($0, $1, $2, $3) => {
|
||||||
|
return `hover (step, ${$3})\n`;
|
||||||
|
});
|
||||||
|
|
||||||
|
code = code.replace(/(click link text)(\s*)(.*)/gi, ($0, $1, $2, $3) => {
|
||||||
|
return `linkByText (step, ${$3})\n`;
|
||||||
|
});
|
||||||
|
|
||||||
code = code.replace(/(click)(\s*)(.*)/gi, ($0, $1, $2, $3) => {
|
code = code.replace(/(click)(\s*)(.*)/gi, ($0, $1, $2, $3) => {
|
||||||
return `click (step, ${$3})\n`;
|
return `click (step, ${$3})\n`;
|
||||||
});
|
});
|
||||||
|
@ -745,10 +757,16 @@ export class GBVMService extends GBService {
|
||||||
code = code.replace(/("[^"]*"|'[^']*')|\bclick\b/gi, ($0, $1) => {
|
code = code.replace(/("[^"]*"|'[^']*')|\bclick\b/gi, ($0, $1) => {
|
||||||
return $1 === undefined ? 'this.click' : $1;
|
return $1 === undefined ? 'this.click' : $1;
|
||||||
});
|
});
|
||||||
|
code = code.replace(/("[^"]*"|'[^']*')|\blinkByText\b/gi, ($0, $1) => {
|
||||||
|
return $1 === undefined ? 'this.linkByText' : $1;
|
||||||
|
});
|
||||||
|
code = code.replace(/("[^"]*"|'[^']*')|\bhover\b/gi, ($0, $1) => {
|
||||||
|
return $1 === undefined ? 'this.hover' : $1;
|
||||||
|
});
|
||||||
code = code.replace(/("[^"]*"|'[^']*')|\bsendEmail\b/gi, ($0, $1) => {
|
code = code.replace(/("[^"]*"|'[^']*')|\bsendEmail\b/gi, ($0, $1) => {
|
||||||
return $1 === undefined ? 'this.sendEmail' : $1;
|
return $1 === undefined ? 'this.sendEmail' : $1;
|
||||||
});
|
});
|
||||||
// await insertion.
|
// await insertion.
|
||||||
|
|
||||||
code = code.replace(/this\./gm, 'await this.');
|
code = code.replace(/this\./gm, 'await this.');
|
||||||
code = code.replace(/\nfunction/i, 'async function');
|
code = code.replace(/\nfunction/i, 'async function');
|
||||||
|
|
|
@ -422,7 +422,7 @@ export class SystemKeywords {
|
||||||
*/
|
*/
|
||||||
public async wait(seconds: number) {
|
public async wait(seconds: number) {
|
||||||
// tslint:disable-next-line no-string-based-set-timeout
|
// tslint:disable-next-line no-string-based-set-timeout
|
||||||
GBLog.info(`BASIC: Talking to a specific user (TALK TO).`);
|
GBLog.info(`BASIC: WAIT for ${seconds} second(s).`);
|
||||||
const timeout = async (ms: number) => new Promise(resolve => setTimeout(resolve, ms));
|
const timeout = async (ms: number) => new Promise(resolve => setTimeout(resolve, ms));
|
||||||
await timeout(seconds * 1000);
|
await timeout(seconds * 1000);
|
||||||
}
|
}
|
||||||
|
@ -575,15 +575,18 @@ export class SystemKeywords {
|
||||||
}
|
}
|
||||||
|
|
||||||
let body = { values: [[]] };
|
let body = { values: [[]] };
|
||||||
for (let index = 0; index < 128; index++) {
|
|
||||||
|
const address = `A2:${this.numberToLetters(args.length - 1)}2`;
|
||||||
|
for (let index = 0; index < args.length; index++) {
|
||||||
let value = args[index];
|
let value = args[index];
|
||||||
if (value && this.isValidDate(value)) {
|
if (value && this.isValidDate(value)) {
|
||||||
value = `'${value}`;
|
value = `'${value}`;
|
||||||
}
|
}
|
||||||
body.values[0][index] = value;
|
body.values[0][index] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
await client
|
await client
|
||||||
.api(`${baseUrl}/drive/items/${document.id}/workbook/worksheets('${sheets.value[0].name}')/range(address='A2:DX2')`)
|
.api(`${baseUrl}/drive/items/${document.id}/workbook/worksheets('${sheets.value[0].name}')/range(address='${address}')`)
|
||||||
.patch(body);
|
.patch(body);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -988,7 +988,7 @@ export class GBMinService {
|
||||||
user.subjects = [];
|
user.subjects = [];
|
||||||
user.cb = undefined;
|
user.cb = undefined;
|
||||||
user.welcomed = false;
|
user.welcomed = false;
|
||||||
user.basicOptions = { maxLines: 100, translatorOn: true, wholeWord: true, theme: "white" };
|
user.basicOptions = { maxLines: 100, translatorOn: true, wholeWord: true, theme: "white", maxColumns: 40 };
|
||||||
|
|
||||||
firstTime = true;
|
firstTime = true;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue