Skip to content

Commit

Permalink
Merge pull request #207 from angrykoala/dev
Browse files Browse the repository at this point in the history
Wendigo 1.3.0
  • Loading branch information
angrykoala authored Oct 1, 2018
2 parents 3242fe4 + 2f9e6ce commit 5bde75d
Show file tree
Hide file tree
Showing 14 changed files with 356 additions and 113 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
1.3.0 / 2018-10-01
==================

* WaitForRequest and waitForResponse will resolve if the request was already made
* WaitForNextRequest and waitForNextResponse added with the past behavior of waitForRequest/Response
* Mock WaitUntilCalled method

1.2.0 / 2018-09-29
==================

Expand Down
17 changes: 12 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -310,16 +310,22 @@ await browser.click("a");
await browser.waitForUrl("my-url");
```


**waitForRequest(url, timeout=500)**
Waits until a request with given url is done.
Waits until a request with given url is done. This will resolve immediately if the requests was already made, to wait without taking in account past requests use `waitForNextRequest`.

```js
await browser.waitForRequest("my-url");
```

**waitForResponse(url, timeout=500)**
Waits until a response to the given url is done.
Waits until a response to the given url is done. This will resolve immediately if the response was already received, to wait without taking in account past requests use `waitForNextResponse`.

**waitForNextRequest(url ,timeout=500)**
Waits until next request with given url is done. If the request was already made, this method will wait until next one.

**waitForNextResponse(url ,timeout=500)**
Waits until next response with given url is received. If the response was already received, this method will wait until next one.


**findByText(selector?, text)**
Returns an array with the elements with text content matching the given text.
Expand Down Expand Up @@ -996,6 +1002,7 @@ Mock will return a RequestMock object, with the following properties:
* `queryString`: The mock queryString
* `immediate`: If the mock will return immediately (delay=0)
* `assert.called(times?)`: asserts that the mock has been called the given number of times, if times parameter is not given, the assertion will throw if no calls were made
* `waitUntilCalled(timeout=500)`: Waits until the mock is called
* `auto`: If the request will be completed automatically

```js
Expand Down Expand Up @@ -1089,13 +1096,13 @@ await browser.filter.url(/api/).method("DELETE").body({id: 5}).requests;
```

**responseBody(expected)**
Filters requests by response body, the body can be a String, Object or regex. This filter returns a promise, so either then or await is required. Also it cannot be concatenated directly.
Filters requests by response body, the body can be a String, Object or regex.

```js
const byResponseFilter = await browser.requests.filter.url(/api/).responseBody({response: 'OK'}).requests;
```

> Keep in mind that some filters like status require the requests to be finished. Use `await browser.wait()` before filtering to make sure the requests was completed.
> Keep in mind that some filters like status require the requests to be finished. Use `await browser.waitForResponse()` before filtering to make sure the requests was completed.
### Requests Assertions
Assertions related requests can be accessed through `browser.assert.request`. Note that in assertions, request is singular.
Expand Down
31 changes: 30 additions & 1 deletion lib/mixins/browser_wait.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,43 @@ module.exports = function BrowserWaitMixin(s) {
}

waitForRequest(url, timeout = 500) {
const waitForPromise = this.waitForNextRequest(url, timeout);

const alreadyRequestsPromise = this.requests.filter.url(url).requests.then((requests) => {
if (requests.length > 0) return Promise.resolve();
else return Promise.reject();
});

return utils.promiseOr([alreadyRequestsPromise, waitForPromise]).catch(() => {
return Promise.reject(new TimeoutError(`Waiting for request "${url}"`, timeout));
});
}

waitForResponse(url, timeout = 500) {
const waitForPromise = this.waitForNextResponse(url, timeout);

const alreadyResponsePromise = this.requests.filter.url(url).requests.then((requests) => {
const responded = requests.filter((request) => {
return Boolean(request.response());
});
if (responded.length > 0) return Promise.resolve();
else return Promise.reject();
});

return utils.promiseOr([alreadyResponsePromise, waitForPromise]).catch(() => {
return Promise.reject(new TimeoutError(`Waiting for response "${url}"`, timeout));
});
}

waitForNextRequest(url, timeout = 500) {
return this.page.waitForRequest(url, {
timeout: timeout
}).catch(() => {
return Promise.reject(new TimeoutError(`Waiting for request "${url}"`, timeout));
});
}

waitForResponse(url, timeout = 500) {
waitForNextResponse(url, timeout = 500) {
return this.page.waitForResponse(url, {
timeout: timeout
}).catch(() => {
Expand Down
22 changes: 20 additions & 2 deletions lib/models/request_mock.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
const EventEmitter = require('events');
const URL = require('url').URL;

const {FatalError, AssertionError} = require('../errors');
const {FatalError, AssertionError, TimeoutError} = require('../errors');
const utils = require('../utils');


Expand Down Expand Up @@ -59,8 +59,26 @@ module.exports = class RequestMock {
this._events.emit("respond");
}

increaseCalled() {
waitUntilCalled(timeout = 500) {
if (this.called) return Promise.resolve();
return new Promise((resolve, reject) => {
let rejected = false;
const tid = setTimeout(() => {
rejected = true;
reject(new TimeoutError(`Wait until mock of "${this.url}" is called`, timeout));
}, timeout);
this._events.once("on-request", () => {
if (!rejected) {
clearTimeout(tid);
resolve();
}
});
});
}

onRequest() {
this._timesCalled++;
this._events.emit("on-request");
}

_assertCalled(times, msg) {
Expand Down
1 change: 1 addition & 0 deletions lib/modules/browser_requests.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ module.exports = class BrowserRequests extends BrowserModule {
}

_respondWithMock(request, mock) {
mock.onRequest();
if (mock.auto && mock.immediate) {
return request.respond(mock.response);
} else if (mock.auto) {
Expand Down
6 changes: 1 addition & 5 deletions lib/request_mocker.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,10 @@ module.exports = class RequestMocker {
getMockedResponse(request) {
const url = new URL(request.url());
const method = request.method();
const mock = this._getMock(`${url.origin}${url.pathname}`, {
return this._getMock(`${url.origin}${url.pathname}`, {
method: method,
queryString: url.search ? utils.parseQueryString(url) : undefined
});
if (mock) { // TODO: move this to request ?
mock.increaseCalled();
return mock;
}
}

mockRequest(url, options) {
Expand Down
17 changes: 17 additions & 0 deletions lib/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,23 @@ module.exports = {
return promise.then(result => func().then(Array.prototype.concat.bind(result)));
}, Promise.resolve([]));
},
promiseOr(promises) { // Returns promise resolve if any promise is resolved, reject otherwise
let resolved = false;
let rejected = 0;
return new Promise((resolve, reject) => {
for (const promise of promises) {
promise.then((res) => {
if (!resolved) {
resolved = true;
resolve(res);
}
}).catch(() => {
rejected++;
if (!resolved && rejected >= promises.length) reject();
});
}
});
},
matchText(text, expected) {
if (expected instanceof RegExp) {
return expected.test(text);
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "wendigo",
"version": "1.2.0",
"version": "1.3.0",
"description": "A proper monster for front-end automated testing",
"engines": {
"node": ">=8.0.0"
Expand Down
6 changes: 6 additions & 0 deletions tests/browser/click.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -113,4 +113,10 @@ describe("Click", function() {
const clickedElements = await browser.clickText("body", "click me delay", 0);
assert.strictEqual(clickedElements, 1);
});

it("Click Label", async() => {
await browser.open(configUrls.forms);
await browser.click("label");
await browser.assert.text("#value-input", "Label");
});
});
43 changes: 43 additions & 0 deletions tests/browser/timezone.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
"use strict";

const assert = require('assert');
const Wendigo = require('../../lib/wendigo');
const configUrls = require('../config.json').urls;


// Skipped until #204 fixed
describe.skip("Timezone", function() {
this.timeout(5000);
let browser;

function getTimezone() {
return browser.evaluate(() => {
return Intl.DateTimeFormat().resolvedOptions().timeZone; // eslint-disable-line new-cap
});
}

after(async() => {
await browser.close();
});

it("Change Timezone To UTC", async() => {
browser = await Wendigo.createBrowser({
timezone: "UTC"
});

await browser.open(configUrls.simple);
const tz = await getTimezone();
assert.strictEqual(tz, "UTC");
});

it("Change Timezone To Japan", async() => {
browser = await Wendigo.createBrowser({
timezone: "Japan"
});
await browser.open(configUrls.simple, {
timezone: "Japan"
});
const tz = await getTimezone();
assert.strictEqual(tz, "Japan");
});
});
66 changes: 66 additions & 0 deletions tests/browser/wait_for_request.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,14 @@ describe("Wait For Request", function() {
await browser.assert.request.url(/api/);
});

it("Wait For Request Already Made", async() => {
await browser.clickText("click me");
await browser.wait(10);
await browser.assert.request.url(/api/).exactly(1);
await browser.waitForRequest("http://localhost:3456/api");
await browser.assert.request.url(/api/).exactly(1);
});

it("Wait For Request With Mock", async() => {
await browser.requests.mock("http://localhost:3456/api");
setTimeout(() => {
Expand All @@ -54,6 +62,18 @@ describe("Wait For Request", function() {
await browser.assert.request.url(/api/).responseBody("test");
});

it("Wait For Response Already Made", async() => {
await browser.requests.mock("http://localhost:3456/api", {
body: "test"
});
await browser.clickText("click me");
await browser.wait(10);
await browser.assert.request.url(/api/).exactly(1);
await browser.assert.request.url(/api/).responseBody("test").exactly(1);
await browser.waitForResponse("http://localhost:3456/api");
await browser.assert.request.url(/api/).responseBody("test").exactly(1);
});

it("Wait For Request Timeout", async() => {
await utils.assertThrowsAsync(async() => {
await browser.waitForRequest("http://localhost:3456/api", 10);
Expand All @@ -65,4 +85,50 @@ describe("Wait For Request", function() {
await browser.waitForResponse("http://localhost:3456/api", 10);
}, `TimeoutError: Waiting for response "http://localhost:3456/api", timeout of 10ms exceeded.`);
});


it("Wait For Next Request", async() => {
setTimeout(() => {
browser.clickText("click me");
}, 100);
await browser.assert.request.url(/api/).exactly(0);
await browser.waitForNextRequest("http://localhost:3456/api");
await browser.assert.request.url(/api/);
});

it("Wait For Next Request Already Made", async() => {
await browser.clickText("click me");
await browser.wait(10);
await browser.assert.request.url(/api/).exactly(1);
await utils.assertThrowsAsync(async() => {
await browser.waitForNextRequest("http://localhost:3456/api", 10);
}, `TimeoutError: Waiting for request "http://localhost:3456/api", timeout of 10ms exceeded.`);
});

it("Wait For Next Response With Mock", async() => {
await browser.requests.mock("http://localhost:3456/api", {
delay: 500,
body: "test"
});
await browser.clickText("click me");
await browser.wait(10);
await browser.assert.request.url(/api/).exactly(1);
await browser.assert.request.url(/api/).responseBody("test").exactly(0);
await browser.waitForNextResponse("http://localhost:3456/api");
await browser.assert.request.url(/api/).responseBody("test");
});

it("Wait For Next Response Already Made", async() => {
await browser.requests.mock("http://localhost:3456/api", {
body: "test"
});
await browser.clickText("click me");
await browser.wait(10);
await browser.assert.request.url(/api/).exactly(1);
await browser.assert.request.url(/api/).responseBody("test").exactly(1);
await utils.assertThrowsAsync(async() => {
await browser.waitForNextResponse("http://localhost:3456/api", 10);
}, `TimeoutError: Waiting for response "http://localhost:3456/api", timeout of 10ms exceeded.`);
await browser.assert.request.url(/api/).responseBody("test").exactly(1);
});
});
Loading

0 comments on commit 5bde75d

Please sign in to comment.