Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix e2e clearValue and add shouldClear to control clearing behavior #117

Merged
merged 8 commits into from
Oct 26, 2020
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 10 additions & 5 deletions adapters/protractor/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,16 +143,21 @@ const adapter: UniDriver<TsSafeElementFinder> = {
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);
}
Expand Down
23 changes: 13 additions & 10 deletions adapters/protractor/src/spec.ts
Original file line number Diff line number Diff line change
@@ -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!');
});
});


18 changes: 11 additions & 7 deletions adapters/puppeteer/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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});
Copy link
Contributor

@GabiGrin GabiGrin Oct 26, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why are 3 clicks needed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

segment-boneyard/nightmare#810 (comment)
Triple click selects all input content

await element.press('Backspace');
};

return {
Expand Down Expand Up @@ -154,17 +153,22 @@ 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
if (disabled) {
return;
}
await element.focus();
await clearValue();
if (shouldClear) {
await clearValue();
}
await element.type(value, {
delay: options?.delay ?? 0,
delay,
});
},
pressKey: async (key) => {
Expand Down
51 changes: 35 additions & 16 deletions adapters/puppeteer/src/spec.ts
Original file line number Diff line number Diff line change
@@ -1,45 +1,64 @@
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')();

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,
});
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!');
});
});
});
20 changes: 10 additions & 10 deletions adapters/selenium/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,11 +83,6 @@ export const seleniumUniDriver = (wep: WebElementGetter): UniDriver<WebElement>
}
};

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();
Expand Down Expand Up @@ -146,16 +141,21 @@ export const seleniumUniDriver = (wep: WebElementGetter): UniDriver<WebElement>
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 clearValue();
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);
}
Expand Down
85 changes: 50 additions & 35 deletions adapters/selenium/src/spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<WebElement>
});
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<WebElement>;
});

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<WebElement>
});
await wd.get(`http://localhost:${port}${getTestAppUrl(data)}`);
const driver = seleniumUniDriver(() => {
const el: any = wd.findElement(By.css('body'));
return el as Promise<WebElement>;
});

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!');
});
});
});
1 change: 1 addition & 0 deletions core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export type UniDriverList<T = any> = {

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<T = any> = {
Expand Down