From c9d0e13e7383785e0228d1ac11d1338e86a5b774 Mon Sep 17 00:00:00 2001 From: gendeld Date: Wed, 21 Oct 2020 14:58:54 +0300 Subject: [PATCH 1/7] Alternative puppeteer clear value implementation --- adapters/puppeteer/src/index.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/adapters/puppeteer/src/index.ts b/adapters/puppeteer/src/index.ts index 5f61078..0c78eef 100644 --- a/adapters/puppeteer/src/index.ts +++ b/adapters/puppeteer/src/index.ts @@ -102,10 +102,9 @@ export const pupUniDriver = ( }; const clearValue = async() => { - const { element, page } = await elem(); - await page.evaluate((element) => { - element.value = ''; - }, element); + const { element } = await elem(); + await element.click({clickCount: 3}); + await element.press('Backspace'); }; return { From 757eed7b7f90e7937de3e6d2e299262f949b3303 Mon Sep 17 00:00:00 2001 From: gendeld Date: Thu, 22 Oct 2020 18:38:07 +0300 Subject: [PATCH 2/7] Use selenium clear --- adapters/selenium/src/index.ts | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/adapters/selenium/src/index.ts b/adapters/selenium/src/index.ts index e8ae326..a34b412 100644 --- a/adapters/selenium/src/index.ts +++ b/adapters/selenium/src/index.ts @@ -83,11 +83,6 @@ export const seleniumUniDriver = (wep: WebElementGetter): UniDriver } }; - const clearValue = async () => { - const el = await elem(); - return el.getDriver().executeScript(`arguments[0].value = '';`, el); - }; - const slowType = async (element: WebElement, value: string, delay: number) => { const driver = await element.getDriver(); @@ -153,7 +148,7 @@ export const seleniumUniDriver = (wep: WebElementGetter): UniDriver if (disabled) { return; } - await clearValue(); + await el.clear(); if (options?.delay) { await slowType(el, value, options.delay); } else { From 3f94a06b63b64c3ba9d1f4cc7e125abcf5c337d5 Mon Sep 17 00:00:00 2001 From: gendeld Date: Thu, 22 Oct 2020 18:52:24 +0300 Subject: [PATCH 3/7] Add should clear option --- adapters/protractor/src/index.ts | 15 ++++++++++----- adapters/puppeteer/src/index.ts | 11 ++++++++--- adapters/selenium/src/index.ts | 15 ++++++++++----- core/src/index.ts | 1 + test-suite/src/run-test-suite.ts | 6 ++++++ 5 files changed, 35 insertions(+), 13 deletions(-) diff --git a/adapters/protractor/src/index.ts b/adapters/protractor/src/index.ts index a5cf55a..cc32365 100644 --- a/adapters/protractor/src/index.ts +++ b/adapters/protractor/src/index.ts @@ -143,16 +143,21 @@ const adapter: UniDriver = { const cm = await (await safeElem()).getAttribute('class'); return cm.split(' ').includes(className); }, - enterValue: async (value: string, options?: EnterValueOptions) => { + enterValue: async ( + value: string, + { delay, shouldClear = true }: EnterValueOptions = {} + ) => { const e = await safeElem(); const disabled = await e.getAttribute("disabled"); // Don't do anything if element is disabled if (disabled) { return; - } - await e.clear(); - if (options?.delay) { - await slowType(element, value, options.delay); + } + if (shouldClear) { + await e.clear(); + } + if (delay) { + await slowType(element, value, delay); } else { await e.sendKeys(value); } diff --git a/adapters/puppeteer/src/index.ts b/adapters/puppeteer/src/index.ts index a5c6ab8..7b03e5a 100644 --- a/adapters/puppeteer/src/index.ts +++ b/adapters/puppeteer/src/index.ts @@ -153,7 +153,10 @@ export const pupUniDriver = ( const cm = await (await element.getProperty('classList')).jsonValue(); return Object.keys(cm).map(key => cm[key]).includes(className); }, - enterValue: async (value: string, options?: EnterValueOptions) => { + enterValue: async ( + value: string, + { delay = 0, shouldClear = true }: EnterValueOptions = {} + ) => { const { element } = await elem(); const disabled = await (await element.getProperty('disabled')).jsonValue(); // Don't do anything if element is disabled @@ -161,9 +164,11 @@ export const pupUniDriver = ( return; } await element.focus(); - await clearValue(); + if (shouldClear) { + await clearValue(); + } await element.type(value, { - delay: options?.delay ?? 0, + delay, }); }, pressKey: async (key) => { diff --git a/adapters/selenium/src/index.ts b/adapters/selenium/src/index.ts index a34b412..608b9d6 100644 --- a/adapters/selenium/src/index.ts +++ b/adapters/selenium/src/index.ts @@ -141,16 +141,21 @@ export const seleniumUniDriver = (wep: WebElementGetter): UniDriver const cl = await el.getAttribute('class'); return cl.split(' ').includes(className); }, - enterValue: async (value: string, options?: EnterValueOptions) => { + enterValue: async ( + value: string, + { delay, shouldClear = true }: EnterValueOptions = {} + ) => { const el = await elem(); const disabled = await el.getAttribute('disabled'); // Don't do anything if element is disabled if (disabled) { return; - } - await el.clear(); - if (options?.delay) { - await slowType(el, value, options.delay); + } + if (shouldClear) { + await el.clear(); + } + if (delay) { + await slowType(el, value, delay); } else { await el.sendKeys(value); } diff --git a/core/src/index.ts b/core/src/index.ts index 0d58d49..daa007c 100644 --- a/core/src/index.ts +++ b/core/src/index.ts @@ -27,6 +27,7 @@ export type UniDriverList = { export type EnterValueOptions = { delay?: number; // Time to wait between key presses in milliseconds. + shouldClear?: boolean; // Whether to try and clear input value before entering text. (default: true) } export type UniDriver = { diff --git a/test-suite/src/run-test-suite.ts b/test-suite/src/run-test-suite.ts index 248a753..ad50da5 100644 --- a/test-suite/src/run-test-suite.ts +++ b/test-suite/src/run-test-suite.ts @@ -92,6 +92,12 @@ export const runTestSuite = (params: TestSuiteParams) => { assert.equal(await driver.$('header input').value(), 'hey there'); }); }); + it(`doesn't attempt to clear value when shouldClear is false`, async() => { + await runTest({items: [], initialText: 'hello'}, async (driver) => { + await driver.$('header input').enterValue(' world'); + assert.equal(await driver.$('header input').value(), 'hello world!'); + }); + }); }); describe('click()', () => { From 9208a940084169a7059d7ddcf1fd888d983bc7dd Mon Sep 17 00:00:00 2001 From: gendeld Date: Thu, 22 Oct 2020 19:34:29 +0300 Subject: [PATCH 4/7] Fix test --- test-suite/src/run-test-suite.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-suite/src/run-test-suite.ts b/test-suite/src/run-test-suite.ts index ad50da5..a02c605 100644 --- a/test-suite/src/run-test-suite.ts +++ b/test-suite/src/run-test-suite.ts @@ -94,7 +94,7 @@ export const runTestSuite = (params: TestSuiteParams) => { }); it(`doesn't attempt to clear value when shouldClear is false`, async() => { await runTest({items: [], initialText: 'hello'}, async (driver) => { - await driver.$('header input').enterValue(' world'); + await driver.$('header input').enterValue(' world!', { shouldClear: false }); assert.equal(await driver.$('header input').value(), 'hello world!'); }); }); From 261e392adde7e8a62a33b50d614df14503762a16 Mon Sep 17 00:00:00 2001 From: gendeld Date: Sun, 25 Oct 2020 11:39:20 +0200 Subject: [PATCH 5/7] Move shouldClear test to adapter specs --- adapters/protractor/src/spec.ts | 23 +++++---- adapters/puppeteer/src/spec.ts | 53 ++++++++++++++------ adapters/selenium/src/spec.ts | 85 +++++++++++++++++++------------- test-suite/src/run-test-suite.ts | 6 --- 4 files changed, 100 insertions(+), 67 deletions(-) diff --git a/adapters/protractor/src/spec.ts b/adapters/protractor/src/spec.ts index f116d0b..2318ae2 100644 --- a/adapters/protractor/src/spec.ts +++ b/adapters/protractor/src/spec.ts @@ -1,24 +1,27 @@ -import { browser, $} from 'protractor'; +import { browser, $ } from 'protractor'; import { SetupFn, runTestSuite, getTestAppUrl } from '@unidriver/test-suite'; import { protractorUniDriver } from '.'; +import { assert } from 'chai'; import { port } from './protractor.conf'; const setup: SetupFn = async (data) => { - await browser.get(`http://localhost:${port}${getTestAppUrl(data)}`); - const driver = protractorUniDriver(() => Promise.resolve($('body'))); + await browser.get(`http://localhost:${port}${getTestAppUrl(data)}`); + const driver = protractorUniDriver(() => Promise.resolve($('body'))); const tearDown = async () => {}; - return {driver, tearDown}; + return { driver, tearDown }; }; describe('protractor', () => { - - runTestSuite({setup}); - + runTestSuite({ setup }); }); describe('protractor specific tests', () => { - + it(`doesn't attempt to clear value when shouldClear is false`, async () => { + const { driver } = await setup({ items: [], initialText: 'hello' }); + await driver + .$('header input') + .enterValue(' world!', { shouldClear: false }); + assert.equal(await driver.$('header input').value(), 'hello world!'); + }); }); - - diff --git a/adapters/puppeteer/src/spec.ts b/adapters/puppeteer/src/spec.ts index 660eb6f..69d543b 100644 --- a/adapters/puppeteer/src/spec.ts +++ b/adapters/puppeteer/src/spec.ts @@ -1,8 +1,14 @@ import * as puppeteer from 'puppeteer'; -import {Browser, Page} from 'puppeteer'; -import {getTestAppUrl, startTestAppServer, SetupFn, runTestSuite} from '@unidriver/test-suite'; -import {pupUniDriver} from './'; -import {Server} from 'http'; +import { Browser, Page } from 'puppeteer'; +import { + getTestAppUrl, + startTestAppServer, + SetupFn, + runTestSuite, +} from '@unidriver/test-suite'; +import { pupUniDriver } from './'; +import { Server } from 'http'; +import { assert } from 'chai'; const port = require('find-free-port-sync')(); @@ -10,36 +16,51 @@ let server: Server; let browser: Browser; let page: Page; -const before = async () => { +const beforeFn = async () => { const args = process.env.CI ? ['--no-sandbox'] : []; const headless = !!process.env.CI; server = await startTestAppServer(port); - browser = await puppeteer.launch({headless, args}); + browser = await puppeteer.launch({ + headless, + args, + executablePath: + '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome', + }); page = await browser.newPage(); }; -const after = async () => { +const afterFn = async () => { server.close(); await page.close(); await browser.close(); }; const setup: SetupFn = async (params) => { - await page.goto(`http://localhost:${port}${getTestAppUrl(params)}`); - const driver = pupUniDriver({ - page, - selector: 'body' - }); + await page.goto(`http://localhost:${port}${getTestAppUrl(params)}`); + const driver = pupUniDriver({ + page, + selector: 'body', + }); - const tearDown = async () => {}; + const tearDown = async () => {}; - return {driver, tearDown}; + return { driver, tearDown }; }; describe('puppeteer', () => { - runTestSuite({setup, before, after}); + runTestSuite({ setup, before: beforeFn, after: afterFn }); }); describe('puppeteer specific tests', () => { - + before(beforeFn); + after(afterFn); + describe('enterValue', () => { + it(`doesn't attempt to clear value when shouldClear is false`, async () => { + const { driver } = await setup({ items: [], initialText: 'hello' }); + await driver + .$('header input') + .enterValue(' world!', { shouldClear: false }); + assert.equal(await driver.$('header input').value(), 'hello world!'); + }); + }); }); diff --git a/adapters/selenium/src/spec.ts b/adapters/selenium/src/spec.ts index 9d501d4..7644139 100644 --- a/adapters/selenium/src/spec.ts +++ b/adapters/selenium/src/spec.ts @@ -3,63 +3,78 @@ import { seleniumUniDriver } from './'; import { Server } from 'http'; import { ThenableWebDriver, Builder, WebElement, By } from 'selenium-webdriver'; import * as chrome from 'selenium-webdriver/chrome'; -import {SetupFn, runTestSuite, startTestAppServer, getTestAppUrl} from '@unidriver/test-suite'; +import { + SetupFn, + runTestSuite, + startTestAppServer, + getTestAppUrl, +} from '@unidriver/test-suite'; +import { assert } from 'chai'; const port = require('find-free-port-sync')(); let server: Server; let wd: ThenableWebDriver; -const before = async () => { - const headless = !!process.env.CI; - const chromeOptions = new chrome.Options(); +const beforeFn = async () => { + const headless = !!process.env.CI; + const chromeOptions = new chrome.Options(); - if (headless) { - chromeOptions.headless(); - } + if (headless) { + chromeOptions.headless(); + } - server = await startTestAppServer(port); - wd = new Builder() - .forBrowser('chrome') - .setChromeOptions(chromeOptions) - .build(); + server = await startTestAppServer(port); + wd = new Builder() + .forBrowser('chrome') + .setChromeOptions(chromeOptions) + .build(); - await wd.get(`http://localhost:${port}${getTestAppUrl({})}`); - - const driver = seleniumUniDriver(() => { - const el: any = wd.findElement(By.css('body')); - return el as Promise - }); + await wd.get(`http://localhost:${port}${getTestAppUrl({})}`); - await driver.wait(); + const driver = seleniumUniDriver(() => { + const el: any = wd.findElement(By.css('body')); + return el as Promise; + }); + + await driver.wait(); }; -const after = async () => { - server.close(); - await wd.quit(); +const afterFn = async () => { + server.close(); + await wd.quit(); }; const setup: SetupFn = async (data) => { - await wd.get(`http://localhost:${port}${getTestAppUrl(data)}`); - const driver = seleniumUniDriver(() => { - const el: any = wd.findElement(By.css('body')); - return el as Promise - }); + await wd.get(`http://localhost:${port}${getTestAppUrl(data)}`); + const driver = seleniumUniDriver(() => { + const el: any = wd.findElement(By.css('body')); + return el as Promise; + }); - const tearDown = async () => { - // await wd.close(); - }; + const tearDown = async () => { + // await wd.close(); + }; - await driver.wait(); + await driver.wait(); - return {driver, tearDown}; + return { driver, tearDown }; }; describe('selenium', () => { - runTestSuite({setup, before, after}); + runTestSuite({ setup, before: beforeFn, after: afterFn }); }); - describe('selenium specific tests', () => { - + before(beforeFn); + after(afterFn); + describe('enterValue', () => { + it(`doesn't attempt to clear value when shouldClear is false`, async () => { + const { driver } = await setup({ items: [], initialText: 'hello' }); + await driver + .$('header input') + .enterValue(' world!', { shouldClear: false }); + assert.equal(await driver.$('header input').value(), 'hello world!'); + }); + }); }); diff --git a/test-suite/src/run-test-suite.ts b/test-suite/src/run-test-suite.ts index a02c605..248a753 100644 --- a/test-suite/src/run-test-suite.ts +++ b/test-suite/src/run-test-suite.ts @@ -92,12 +92,6 @@ export const runTestSuite = (params: TestSuiteParams) => { assert.equal(await driver.$('header input').value(), 'hey there'); }); }); - it(`doesn't attempt to clear value when shouldClear is false`, async() => { - await runTest({items: [], initialText: 'hello'}, async (driver) => { - await driver.$('header input').enterValue(' world!', { shouldClear: false }); - assert.equal(await driver.$('header input').value(), 'hello world!'); - }); - }); }); describe('click()', () => { From cbab9abb806b833f9a41adf9b12c5e12e44ff6ed Mon Sep 17 00:00:00 2001 From: gendeld Date: Sun, 25 Oct 2020 11:54:12 +0200 Subject: [PATCH 6/7] Remove local change --- adapters/puppeteer/src/spec.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/adapters/puppeteer/src/spec.ts b/adapters/puppeteer/src/spec.ts index 69d543b..b65896a 100644 --- a/adapters/puppeteer/src/spec.ts +++ b/adapters/puppeteer/src/spec.ts @@ -23,8 +23,6 @@ const beforeFn = async () => { browser = await puppeteer.launch({ headless, args, - executablePath: - '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome', }); page = await browser.newPage(); }; From e753876345c26d37f5b69426c6e2ccaf93ab298f Mon Sep 17 00:00:00 2001 From: gendeld Date: Mon, 26 Oct 2020 15:02:11 +0200 Subject: [PATCH 7/7] Add comment to explain triple click --- adapters/puppeteer/src/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/adapters/puppeteer/src/index.ts b/adapters/puppeteer/src/index.ts index 7b03e5a..920118c 100644 --- a/adapters/puppeteer/src/index.ts +++ b/adapters/puppeteer/src/index.ts @@ -103,6 +103,7 @@ export const pupUniDriver = ( const clearValue = async() => { const { element } = await elem(); + // Select all input text await element.click({clickCount: 3}); await element.press('Backspace'); };