Skip to content

Commit

Permalink
Merge pull request #44 from newsuk/execute-script-feature
Browse files Browse the repository at this point in the history
feat: execute selenium script
  • Loading branch information
L0wry authored Jun 27, 2018
2 parents 35a4893 + 1207156 commit 017e047
Show file tree
Hide file tree
Showing 6 changed files with 104 additions and 116 deletions.
34 changes: 25 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
# Aye Spy

### Aye Spy with my little eye... a visual regression!

Aye spy is a high performance visual regression tool. Created to fit in with your cloud infrastructure and distribute tests using selenium grid for huge performance gains.

In order to get the most out of Aye Spy we recommend using a selenium grid and cloud storage (currently supporting Amazon S3). However if you wish to run locally that is also supported but the performance gains will be less significant.


## Inspiration

We have taken inspiration for this project from existing projects such as Wraith and BackstopJs.
We have taken inspiration for this project from existing projects such as Wraith and BackstopJs.

Visual regressions testing is a great tool to have in your pipeline but the current solutions on the market were missing one key component we felt was essential for a great developer experience... performance!

Expand All @@ -20,7 +20,7 @@ With the correct set up you can expect your tests using aye-spy to take under a

To install the package:

```npm i -g aye-spy```
`npm i -g aye-spy`

In order to use the remote functionality you will need to export some aws credentials:

Expand All @@ -31,7 +31,7 @@ export AWS_ACCESS_KEY_ID=keyid

Create an S3 bucket to store your images. It will also need to have the correct permissions set up.

Example cofig:
Example config:

```
{
Expand All @@ -54,12 +54,30 @@ Example cofig:
"value": "cookie_value"
}
],
"waitForSelector": ["#section-news"]
"waitForSelector": ["#section-news"],
"onReadyScript": './scripts/clickSelector.js'
}
]
}
```
```

## Custom Scripts

For scenarios where you need to interact with the page before taking a screenshot, a custom script can be used which contains the selenium webdriver actions. The onReadyScript property takes a string path to the the script to be executed.

Only es5 is currently supported so please transpile.

Example script:

```
const By = require('selenium-webdriver').By;
const clickElement = async browser => {
await browser.findElement(By.css('#buttonId"]')).click();
};
module.exports = clickElement;
```

## Running

Expand All @@ -75,8 +93,6 @@ Run the comparison:

`ayespy compare --browser chrome --config config.json --remote`

Generate the comparison report:
Generate the comparison report:

`ayespy generate-report --browser chrome --config config.json --remote`


7 changes: 7 additions & 0 deletions src/__mocks__/seleniumMock.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/* globals jest */

const seleniumMockFunction = jest
.fn()
.mockImplementation(driver => Promise.resolve()); //eslint-disable-line no-unused-vars

module.exports = seleniumMockFunction;
4 changes: 3 additions & 1 deletion src/getScreenshots.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ export default (SnapShotter, config) =>
cookies: scenario.cookies,
removeSelectors: scenario.removeSelectors,
waitForSelector: scenario.waitForSelector,
url: scenario.url
url: scenario.url,
onBeforeScript: scenario.onBeforeScript,
onReadyScript: scenario.onReadyScript
},
{ webdriver, By, until }
);
Expand Down
22 changes: 21 additions & 1 deletion src/snapshotter.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
/* eslint-disable import/no-dynamic-require*/

import fs from 'fs';
import path from 'path';
import logger from './logger';

export default class SnapShotter {
Expand All @@ -14,7 +17,9 @@ export default class SnapShotter {
removeSelectors,
waitForSelector,
url = 'http://localhost:80',
viewportLabel = 'viewportLabel'
viewportLabel = 'viewportLabel',
onBeforeScript,
onReadyScript
},
selenium
) {
Expand All @@ -28,6 +33,8 @@ export default class SnapShotter {
this._removeSelectors = removeSelectors;
this._waitForSelector = waitForSelector;
this._url = url;
this._onBeforeScript = onBeforeScript;
this._onReadyScript = onReadyScript;
this._viewportLabel = viewportLabel;
this._By = selenium.By;
this._until = selenium.until;
Expand Down Expand Up @@ -94,6 +101,15 @@ export default class SnapShotter {
}
}

async executeScript(script) {
try {
const scriptToExecute = require(path.resolve(script));
await scriptToExecute(this._driver);
} catch (error) {
logger.error('snapshotter', `❌ Unable to run script due to: ${error}`);
}
}

async takeSnap() {
try {
logger.info(
Expand All @@ -102,10 +118,14 @@ export default class SnapShotter {
);
await this.driver.get(this._url);

if (this._onBeforeScript) await this.executeScript(this._onBeforeScript);

if (this._cookies) await this.applyCookies();

if (this._waitForSelector) await this.waitForSelector();

if (this._onReadyScript) await this.executeScript(this._onReadyScript);

if (this._removeSelectors) await this.removeTheSelectors();

fs.writeFileSync(
Expand Down
42 changes: 42 additions & 0 deletions src/snapshotter.test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
/* globals jest expect */
import webdriver, { By, until } from './__mocks__/selenium-webdriver';
import SnapShotter from './snapshotter';
import seleniumMock from './__mocks__/seleniumMock';
import logger from './logger';

jest.mock('fs');

Expand Down Expand Up @@ -124,4 +126,44 @@ describe('The snapshotter', () => {
await mockSnapshot.takeSnap();
expect(mockSnapshot.driver.addCookie.mock.calls.length).toBe(2);
});

it('Executes the onBefore script', async () => {
const config = {
gridUrl: 'https://lol.com',
url: 'http://cps-render-ci.elb.tnl-dev.ntch.co.uk/',
label: '1homepage',
onBeforeScript: './src/__mocks__/seleniumMock.js'
};

const mockSnapshot = new SnapShotter(config, { webdriver, By, until });
await mockSnapshot.takeSnap();
expect(seleniumMock).toBeCalledWith(mockSnapshot.driver);
});

it('Executes the onReady script', async () => {
const config = {
gridUrl: 'https://lol.com',
url: 'http://cps-render-ci.elb.tnl-dev.ntch.co.uk/',
label: '1homepage',
onReadyScript: './src/__mocks__/seleniumMock.js'
};

const mockSnapshot = new SnapShotter(config, { webdriver, By, until });
await mockSnapshot.takeSnap();
expect(seleniumMock).toBeCalledWith(mockSnapshot.driver);
});

it.only('Throws an error if incorrect script file is provided', async () => {
const config = {
gridUrl: 'https://lol.com',
url: 'http://cps-render-ci.elb.tnl-dev.ntch.co.uk/',
label: '1homepage',
onReadyScript: '/brokenfile.js'
};

logger.error = jest.fn();
const mockSnapshot = new SnapShotter(config, { webdriver, By, until });
await mockSnapshot.takeSnap();
expect(logger.error.mock.calls.length).toBe(1);
});
});
Loading

0 comments on commit 017e047

Please sign in to comment.