diff --git a/packages/webdriver-utils/src/driver.js b/packages/webdriver-utils/src/driver.js index bcadfc4a7..2bdd428e7 100644 --- a/packages/webdriver-utils/src/driver.js +++ b/packages/webdriver-utils/src/driver.js @@ -87,6 +87,7 @@ export default class Driver { } async findElementXpath(xpath) { + xpath = xpath.replace(/'/g, '"'); const command = { script: `return document.evaluate('${xpath}', document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue.getBoundingClientRect();`, args: [] }; const response = await this.executeScript(command); return response.value; diff --git a/packages/webdriver-utils/src/providers/genericProvider.js b/packages/webdriver-utils/src/providers/genericProvider.js index c40449ad5..61922f03a 100644 --- a/packages/webdriver-utils/src/providers/genericProvider.js +++ b/packages/webdriver-utils/src/providers/genericProvider.js @@ -36,7 +36,7 @@ export default class GenericProvider { this.statusBarHeight = 0; this.pageXShiftFactor = 0; this.pageYShiftFactor = 0; - this.currentOperatingSystem = null; + this.currentTag = null; this.removeElementShiftFactor = 50000; this.initialScrollFactor = { value: [0, 0] }; } @@ -70,13 +70,13 @@ export default class GenericProvider { } async getInitialPosition() { - if (this.currentOperatingSystem === 'iOS') { + if (this.currentTag.osName === 'iOS') { this.initialScrollFactor = await this.driver.executeScript({ script: 'return [parseInt(window.scrollX), parseInt(window.scrollY)];', args: [] }); } } async scrollToInitialPosition(x, y) { - if (this.currentOperatingSystem === 'iOS') { + if (this.currentTag.osName === 'iOS') { await this.driver.executeScript({ script: `window.scrollTo(${x}, ${y})`, args: [] }); } } @@ -104,7 +104,7 @@ export default class GenericProvider { const tiles = await this.getTiles(this.header, this.footer, fullscreen); log.debug(`[${name}] : Tiles ${JSON.stringify(tiles)}`); - this.currentOperatingSystem = tag.osName; + this.currentTag = tag; this.statusBarHeight = tiles.tiles[0].statusBarHeight; const ignoreRegions = await this.findRegions( @@ -210,7 +210,7 @@ export default class GenericProvider { async getRegionObjectFromBoundingBox(selector, element) { const scaleFactor = await this.metaData.devicePixelRatio(); let headerAdjustment = 0; - if (this.currentOperatingSystem === 'iOS') { + if (this.currentTag.osName === 'iOS') { headerAdjustment = this.statusBarHeight; } const coOrdinates = { @@ -246,9 +246,13 @@ export default class GenericProvider { async updatePageShiftFactor(location, scaleFactor) { const scrollFactors = await this.driver.executeScript({ script: 'return [parseInt(window.scrollX), parseInt(window.scrollY)];', args: [] }); - this.pageYShiftFactor = this.currentOperatingSystem === 'iOS' ? this.statusBarHeight : (this.statusBarHeight - (scrollFactors.value[1] * scaleFactor)); - this.pageXShiftFactor = this.currentOperatingSystem === 'iOS' ? 0 : (-(scrollFactors.value[0] * scaleFactor)); - if (this.currentOperatingSystem === 'iOS') { + if (this.currentTag.osName === 'iOS' || (this.currentTag.osName === 'OS X' && parseInt(this.currentTag.browserVersion) > 13 && this.currentTag.browserName.toLowerCase() === 'safari')) { + this.pageYShiftFactor = this.statusBarHeight; + } else { + this.pageYShiftFactor = this.statusBarHeight - (scrollFactors.value[1] * scaleFactor); + } + this.pageXShiftFactor = this.currentTag.osName === 'iOS' ? 0 : (-(scrollFactors.value[0] * scaleFactor)); + if (this.currentTag.osName === 'iOS') { if (scrollFactors.value[0] !== this.initialScrollFactor.value[0] || scrollFactors.value[1] !== this.initialScrollFactor.value[1]) { this.pageXShiftFactor = (-1 * this.removeElementShiftFactor); this.pageYShiftFactor = (-1 * this.removeElementShiftFactor); diff --git a/packages/webdriver-utils/test/providers/genericProvider.test.js b/packages/webdriver-utils/test/providers/genericProvider.test.js index 0e44dcdcb..822b94437 100644 --- a/packages/webdriver-utils/test/providers/genericProvider.test.js +++ b/packages/webdriver-utils/test/providers/genericProvider.test.js @@ -272,7 +272,7 @@ describe('GenericProvider', () => { provider = new GenericProvider('123', 'http:executorUrl', { platform: 'win' }, {}); await provider.createDriver(); spyOn(Driver.prototype, 'executeScript').and.returnValue({ value: [0, 10] }); - provider.currentOperatingSystem = 'iOS'; + provider.currentTag = { osName: 'iOS' }; provider.pageYShiftFactor = 0; provider.statusBarHeight = 0; }); @@ -310,11 +310,52 @@ describe('GenericProvider', () => { }); }); + describe('When OS X', () => { + beforeEach(async () => { + provider = new GenericProvider('123', 'http:executorUrl', { platform: 'OS X' }, {}); + await provider.createDriver(); + spyOn(Driver.prototype, 'executeScript').and.returnValue({ value: [0, 10] }); + provider.currentTag = { osName: 'OS X' }; + provider.pageYShiftFactor = 0; + provider.statusBarHeight = 0; + }); + + describe('When Safari browserVersion > 13', () => { + describe('when element is visible in viewport', () => { + beforeEach(() => { + provider.initialScrollFactor = { value: [0, 10] }; + provider.currentTag.browserName = 'safari'; + provider.currentTag.browserVersion = 15; + }); + + it('should not update pageYShiftFactor for OS X if scrolled', async () => { + await provider.updatePageShiftFactor({ y: 0 }, 1); + expect(provider.pageYShiftFactor).toBe(0); + }); + }); + }); + + describe('When Safari browserVersion <= 13', () => { + describe('when element is visible in viewport', () => { + beforeEach(() => { + provider.initialScrollFactor = { value: [0, 10] }; + provider.currentTag.browserName = 'safari'; + provider.currentTag.browserVersion = 13; + }); + + it('should update pageYShiftFactor for OS X platforms accordingly if scrolled', async () => { + await provider.updatePageShiftFactor({ y: 0 }, 1); + expect(provider.pageYShiftFactor).toBe(-10); + }); + }); + }); + }); + describe('When Other', () => { beforeEach(async () => { provider = new GenericProvider('123', 'http:executorUrl', { platform: 'win' }, {}); await provider.createDriver(); - provider.currentOperatingSystem = 'Android'; + provider.currentTag = { osName: 'Android' }; provider.pageYShiftFactor = 0; }); @@ -340,6 +381,7 @@ describe('GenericProvider', () => { beforeEach(async () => { // mock metadata provider = new GenericProvider('123', 'http:executorUrl', { platform: 'win' }, {}); + provider.currentTag = { osName: 'Windows' }; await provider.createDriver(); spyOn(DesktopMetaData.prototype, 'devicePixelRatio') .and.returnValue(1); @@ -370,6 +412,7 @@ describe('GenericProvider', () => { beforeEach(async () => { // mock metadata provider = new GenericProvider('123', 'http:executorUrl', { platform: 'win' }, {}); + provider.currentTag = { osName: 'iOS' }; await provider.createDriver(); spyOn(DesktopMetaData.prototype, 'devicePixelRatio') .and.returnValue(1); @@ -381,6 +424,7 @@ describe('GenericProvider', () => { afterEach(() => { provider.pageYShiftFactor = 0; + provider.currentTag = null; }); it('should return a JSON object with the correct selector and coordinates', async () => { await provider.createDriver(); @@ -407,6 +451,7 @@ describe('GenericProvider', () => { beforeEach(async () => { // mock metadata provider = new GenericProvider('123', 'http:executorUrl', { platform: 'win' }, {}); + provider.currentTag = { osName: 'Windows' }; await provider.createDriver(); spyOn(DesktopMetaData.prototype, 'devicePixelRatio') .and.returnValue(1); @@ -432,7 +477,7 @@ describe('GenericProvider', () => { describe('When iOS', () => { beforeEach(() => { - provider.currentOperatingSystem = 'iOS'; + provider.currentTag = { osName: 'iOS' }; provider.statusBarHeight = 132; }); it('should return a JSON object with the correct selector and coordinates with added statusBarHeight', async () => { @@ -525,6 +570,7 @@ describe('GenericProvider', () => { let provider; beforeEach(async () => { provider = new GenericProvider('123', 'http:executorUrl', { platform: 'win' }, {}); + provider.currentTag = { osName: 'Windows' }; await provider.createDriver(); }); describe('when not IOS', () => { @@ -537,12 +583,12 @@ describe('GenericProvider', () => { describe('when IOS', () => { let executeScriptSpy; beforeEach(() => { - provider.currentOperatingSystem = 'iOS'; + provider.currentTag = { osName: 'iOS' }; executeScriptSpy = spyOn(Driver.prototype, 'executeScript'); }); afterEach(() => { - provider.currentOperatingSystem = null; + provider.currentTag = null; }); it('should get the initial scroll position', async () => { spyOn(Driver.prototype, 'executeScript').and.returnValue({ value: [0, 200] }); @@ -557,6 +603,7 @@ describe('GenericProvider', () => { let provider; beforeEach(async () => { provider = new GenericProvider('123', 'http:executorUrl', { platform: 'win' }, {}); + provider.currentTag = { osName: 'Windows' }; await provider.createDriver(); }); describe('when not IOS', () => { @@ -569,13 +616,13 @@ describe('GenericProvider', () => { describe('when IOS', () => { let executeScriptSpy; beforeEach(() => { - provider.currentOperatingSystem = 'iOS'; + provider.currentTag = { osName: 'iOS' }; provider.initialScrollFactor = { value: [0, 50] }; executeScriptSpy = spyOn(Driver.prototype, 'executeScript'); }); afterEach(() => { - provider.currentOperatingSystem = null; + provider.currentTag = null; }); it('should scroll to position', async () => { await provider.scrollToInitialPosition(0, 50);