Skip to content

Commit

Permalink
Merge pull request #60 from angrykoala/dev
Browse files Browse the repository at this point in the history
0.3.2
  • Loading branch information
angrykoala authored Feb 16, 2018
2 parents 02abc7c + c48f7d2 commit 3291ed3
Show file tree
Hide file tree
Showing 17 changed files with 437 additions and 132 deletions.
10 changes: 9 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
0.3.2 / 2018-02-16
==================

* Attribute and not attribute assertions
* browser.attribute method
* browser.click and browser.clickText throws if no element is found, return the number of elements
* Puppeteer settings are now passed down in createBrowser, including slowMo
* Minor improvements in assertion messages

0.3.1 / 2018-02-09
==================

* Method browser.clickText
* Find by text fixed to return valid html elements


0.3.0 / 2018-02-07
==================

Expand Down
52 changes: 47 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,11 @@ Will create and return a [Browser](#Browser) instance. It will automatically lau

* _settings_ is an optional object with the settings to build the browser
* `log: false`: If true, it will log all the console events of the browser.
* `headless: true`: If true, the browser will run on headless mode.
* Any settings that can be passed to puppeteer can be passed in createdBrowser, for example:
* `headless: true`: If true, the browser will run on headless mode.
* `slowMo: 0`: Slows the execution of commands by given number of milliseconds

> **Warning:** the settings will only take effect the first time a browser page is created, to fully restart the settings you must close the browser connection using `Wendigo.stop()` before executing createBrowser again
Example:
```js
Expand Down Expand Up @@ -139,7 +143,18 @@ const classes=await browser.class(node); // Returns ["container", "main", "anoth
Returns the value of the first element with given selector. Returns _null_ if no element or value found.

```js
const value=await browser.value("input.my-input");
const value = await browser.value("input.my-input");
```

**attribute(selector, attributeName)**
Return the attribute value of the first element found with given selector. Throws if no element is found. Returns `""` if the attribute is set but no value is given and `null` if the attribute doesn't exists.

```js
const classAttribute = await browser.attribute(".my-element", "class"); // Returns "my-element another-class"

const hiddentAttr = await browser.attribute(".my-hidden-element", "hidden"); // Returns ""
const hiddentAttr2 = await browser.attribute(".not-hidden-element", "hidden"); // Returns null

```

**text(selector)**
Expand Down Expand Up @@ -241,7 +256,7 @@ await browser.assert.text("p", "My First Paragraph");
Asserts that at least one element matching the given selector contains the expected text.

```js
await browser.assert.text("p", "My First");
await browser.assert.textContains("p", "My First");
```

**title(expected, msg)**
Expand Down Expand Up @@ -291,6 +306,20 @@ browser.assert.elements("p.second", 2); // Fails
browser.assert.elements("p.second", {atLeast: 1}); // Ok
```

**attribute(selector, attribute, expected, msg)**
Asserts that the first element matching the given selector contains an attribute matching the expected value. If no expected value is given, any not null value for the attribute will pass.

```js
browser.assert.attribute(".hidden-class", "class", "hidden-class");
browser.assert.attribute(".hidden-class", "hidden");
```

To pass a custom message without specifying an expected value, you can pass null:
```js
browser.assert.attribute(".hidden-class", "hidden", null, "hidden-class doesn't have attribute hidden");
```

If the element doesn't exists, the assertion will fail.

### Negative assertions
Most of the browser assertions have a negative version that can be used with `browser.assert.not`. Most of the behaviours of the "not" assertions are simply the inverse of the positive version.
Expand All @@ -308,7 +337,7 @@ Asserts that the first element with given selector is not visible. If no element
**not.text(selector, expected, msg)**
Asserts that no element matching the given selector matches the expected text.

```
```js
await browser.assert.not.text("p", "This text doesn't exists");
```

Expand All @@ -321,6 +350,19 @@ Asserts that the url of the page doesn't match the expected string.
**not.value(selector, expected, msg)**
Asserts that the first element with the given selector doesn't have the expected value.

**not.attribute(selector, attribute, expected, msg)**
Asserts that the first element matching the given selector doesn't contain an attribute with the expected value. If no expected value is given, any not null value on the attribute will fail.

```js
browser.assert.not.attribute(".not-hidden-class", "class", "hidden-class");
browser.assert.not.attribute(".not-hidden-class", "hidden");
```

To pass a custom message without specifying an expected value, you can pass null:
```js
browser.assert.not.attribute(".hidden-class", "href", null, "hidden-class has attribute href");
```
If the element doesn't exists, the assertion will fail.

## Examples

Expand Down Expand Up @@ -365,7 +407,7 @@ describe("My Tests", function() {
### Running Tests With Travis CI
Running tests using puppeteer's require disabling the sandbox running mode. This can easily be achieved by passing the environment variable `NO_SANDBOX=true`, this can be done either as part of the test execution command, as a Travis secret env variable or in the `.travis.yml` file itself:

```ỳml
```yml
language: node_js
os:
- linux
Expand Down
13 changes: 10 additions & 3 deletions lib/browser.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,15 +45,20 @@ module.exports = class Browser extends BrowserBase {
if(index > elements.length || index < 0) {
return Promise.reject(new Error(`browser.click, invalid index "${index}" for selector "${selector}", ${elements.length} elements found.`));
}
return elements[index].click();
elements[index].click();
return 1;
} else{
return Promise.all(elements.map((e) => e.click()));
if(elements.length <= 0) return Promise.reject(new Error(`No element "${selector}" found when trying to click.`));
return Promise.all(elements.map((e) => e.click())).then(() => {
return elements.length;
});
}
});
}

clickText(text) {
return this.findByText(text).then((elements) => {
if(elements.length <= 0) return Promise.reject(new Error(`No element with text "${text}" found when trying to click.`));
return this.click(elements);
});
}
Expand Down Expand Up @@ -81,7 +86,9 @@ module.exports = class Browser extends BrowserBase {
}

waitFor(selector, timeout = 500) {
return this.frame.waitForSelector(selector, {timeout: timeout});
return this.frame.waitForSelector(selector, {timeout: timeout}).catch(() => {
return Promise.reject(new Error(`Waiting for element "${selector}" failed, timeout of ${timeout}ms exceeded`));
});
}

findByText(text) {
Expand Down
28 changes: 25 additions & 3 deletions lib/browser_assertions.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,13 @@
const assert = require('assert');
const BrowserNotAssertions = require('./browser_not_assertions');
const elementsAssertionUtils = require('./assertions_utils/assert_elements');
const utils = require('./utils');

module.exports = class BrowserAssertions {

constructor(browser) {
this._browser = browser;
this.not = new BrowserNotAssertions(this);
this.not = new BrowserNotAssertions(this, browser);
}

exists(selector, msg) {
Expand Down Expand Up @@ -45,7 +46,7 @@ module.exports = class BrowserAssertions {
const foundText = texts.length === 0 ? "no text" : `"${texts.join(" ")}"`;
msg = `Expected element "${selector}" to contain text "${expected}", ${foundText} found`;
}
for(const text of texts){
for(const text of texts) {
if(text && text.includes(expected)) return Promise.resolve();
}
assert(false, msg);
Expand Down Expand Up @@ -103,5 +104,26 @@ module.exports = class BrowserAssertions {
});
}


attribute(selector, attribute, expectedValue, msg) {
return this._browser.attribute(selector, attribute).then((value) => {
if(expectedValue === undefined || expectedValue === null) {
if(!msg) msg = `Expected element "${selector}" to have attribute "${attribute}".`;
assert((value !== null), msg);
} else {
if(!msg) {
msg = `Expected element "${selector}" to have attribute "${attribute}" with value "${expectedValue}"`;
if(value) msg = `${msg}, "${value}" found.`;
else msg = `${msg}.`;
}
assert.strictEqual(value, expectedValue, msg);
}
}).catch(() => {
if(!msg) {
msg = `Expected element "${selector}" to have attribute "${attribute}"`;
if(expectedValue !== undefined) msg = `${msg} with value "${expectedValue}"`;
msg = `${msg}, no element found.`;
}
return utils.rejectAssertion(msg);
});
}
};
10 changes: 10 additions & 0 deletions lib/browser_base.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,14 @@ module.exports = class BrowserBase {
else return element.value;
}, selector);
}

attribute(selector, attributeName) {
return this.page.evaluate((q, attributeName) => {
const element = WendigoUtils.queryElement(q);
if(!element) return Promise.reject();
return element.getAttribute(attributeName);
}, selector, attributeName).catch(() => {
return Promise.reject(new Error(`Element "${selector}" not found when trying to get attribute "${attributeName}".`));
});
}
};
24 changes: 23 additions & 1 deletion lib/browser_not_assertions.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"use strict";

const assert = require('assert');
const utils = require('./utils');

function invertify(cb, msg) {
return cb().then(() => {
Expand All @@ -12,8 +13,9 @@ function invertify(cb, msg) {

module.exports = class BrowserAssertions {

constructor(browserAssertions) {
constructor(browserAssertions, browser) {
this._assertions = browserAssertions;
this._browser = browser;
}


Expand Down Expand Up @@ -66,4 +68,24 @@ module.exports = class BrowserAssertions {
}, msg);
}

attribute(selector, attribute, expectedValue, msg) {
return this._browser.attribute(selector, attribute).then((value) => {
if(expectedValue === undefined || expectedValue === null) {
if(!msg) msg = `Expected element "${selector}" not to have attribute "${attribute}".`;
assert((value === null), msg);
} else {
if(!msg) {
msg = `Expected element "${selector}" not to have attribute "${attribute}" with value "${expectedValue}".`;
}
assert(value !== expectedValue, msg);
}
}).catch(() => {
if(!msg) {
msg = `Expected element "${selector}" not to have attribute "${attribute}"`;
if(expectedValue !== undefined) msg = `${msg} with value "${expectedValue}"`;
msg = `${msg}, no element found.`;
}
return utils.rejectAssertion(msg);
});
}
};
6 changes: 5 additions & 1 deletion lib/utils.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
"use strict";

const assert = require('assert');

module.exports = {
isNumber(n) {
return !Number.isNaN(Number(n));
},
rejectAssertion(msg) {
return Promise.reject(new assert.AssertionError({message: msg}));
}

};
9 changes: 5 additions & 4 deletions lib/wendigo.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ const puppeteer = require('puppeteer');

const defaultSettings = {
log: false,
headless: true
headless: true,
args: [],
slowMo: 0
};

module.exports = class Wendigo {
Expand All @@ -27,11 +29,10 @@ module.exports = class Wendigo {
}

static async _setInstance(settings) {
let args = [];
if(process.env["NO_SANDBOX"]) {
args = ['--no-sandbox', '--disable-setuid-sandbox']; // Required to run in travis
settings.args = settings.args.concat(['--no-sandbox', '--disable-setuid-sandbox']); // Required to run in travis
}
if(!this.instance) this.instance = await puppeteer.launch({headless: settings.headless, args: args});
if(!this.instance) this.instance = await puppeteer.launch(settings);
}

};
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
{
"name": "wendigo",
"version": "0.3.1",
"version": "0.3.2",
"description": "A proper monster for front-end testing",
"engines": {
"node": ">=8.9.4"
},
"main": "lib/wendigo.js",
"scripts": {
"test": "mocha tests"
"test": "mocha tests --recursive"
},
"repository": {
"type": "git",
Expand Down
Loading

0 comments on commit 3291ed3

Please sign in to comment.