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

fixes #1 - handling multiple xhrs #3

Merged
merged 2 commits into from
Jan 5, 2019
Merged
Show file tree
Hide file tree
Changes from all 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
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@
"scripts": {
"prettier:write": "prettier --single-quote --trailing-comma es5 --write src/**/*",
"lint": "eslint src",
"test": "jest --forceExit",
"test:coverage": "jest --coverage --forceExit",
"test": "jest",
"test:coverage": "jest --coverage",
"precommit": "lint-staged",
"build": "rollup -c",
"publish:patch": "yarn publish --patch"
Expand Down
184 changes: 112 additions & 72 deletions src/__tests__/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,143 +18,183 @@ OK_NO_XHR
</html>
`;

const OK_WITH_1_FAIL_XHR = `
<html>
OK_WITH_1_SLOW_XHR
<script>
var xmlhttp = new XMLHttpRequest();
var url = 'http://localhost:${xhrBackendPort}/fail';

xmlhttp.open("GET", url, true);
xmlhttp.send();

</script>
</html>
`;

const OK_WITH_1_XHR = `
<html>
OK_WITH_1_SLOW_XHR
<script>
var xmlhttp = new XMLHttpRequest();
var url = 'http://localhost:${xhrBackendPort}';
var url = 'http://localhost:${xhrBackendPort}/request1';

xmlhttp.open("GET", url, true);
xmlhttp.send();
xmlhttp.send();

</script>
</html>
`;

const OK_WITH_1_SLOW_XHR = `
const OK_WITH_2_XHR = `
<html>
OK_WITH_1_SLOW_XHR
<script>
setTimeout(() => {
var xmlhttp = new XMLHttpRequest();
var url = 'http://localhost:${xhrBackendPort}/infinite';
var url = 'http://localhost:${xhrBackendPort}/request1';

xmlhttp.open("GET", url, true);
xmlhttp.send();
}, 10);

xmlhttp.send();

var xmlhttp2 = new XMLHttpRequest();
var url2 = 'http://localhost:${xhrBackendPort}/request2';

xmlhttp2.open("GET", url2, true);
xmlhttp2.send();

</script>
</html>
`;

const requestHandler = (request, response) => {
if (request.url === '/with_infinite_xhr') {
response.statusCode = 200;
response.end(OK_WITH_1_SLOW_XHR);
} else if (request.url === '/with_xhr') {
response.statusCode = 200;
response.end(OK_WITH_1_XHR);
} else if (request.url === '/with_xhr_failing') {
response.statusCode = 200;
response.end(OK_WITH_1_FAIL_XHR);
} else {
response.statusCode = 200;
response.end(OK_NO_XHR);
}
let request1Resolver;
const request1Promise = () => {
return new Promise(resolve => {
request1Resolver = resolve;
});
};

let request2Resolver;
const request2Promise = () => {
return new Promise(resolve => {
request2Resolver = resolve;
});
};

const backendRequestHandler = (request, response) => {
if (request.url === '/infinite') {
// This xhr will never end
} else if (request.url === '/fail') {
response.statusCode = 500;
response.end('boom');
} else {
response.end();
const backendRequestHandler = async (request, response) => {
if (request.url === '/request1') {
const [statusCode, body] = await request1Promise();
response.statusCode = statusCode;
response.end(body);
} else if (request.url === '/request2') {
const [statusCode, body] = await request2Promise();
response.statusCode = statusCode;
response.end(body);
}
};

let server;
let backendServer;
let browser;

beforeEach(async () => {
server = http.createServer(requestHandler);
await server.listen(port);
describe('PendingXHR', () => {
beforeEach(async () => {
backendServer = http.createServer(backendRequestHandler);
await backendServer.listen(xhrBackendPort);

const args = [];
if (process.env.CI) {
args.push('--no-sandbox');
}
browser = await puppeteer.launch({
headless: true,
args,
});
});

backendServer = http.createServer(backendRequestHandler);
await backendServer.listen(xhrBackendPort);
afterEach(async () => {
await browser.close();
if (request1Resolver) {
await request1Resolver();
}
});

const args = [];
if (process.env.CI) {
args.push('--no-sandbox');
}
browser = await puppeteer.launch({
headless: true,
args,
afterEach(cb => {
backendServer.close(cb);
});
});

afterEach(async () => {
await server.close();
await backendServer.close();
});
afterEach(cb => {
server.close(cb);
});

async function startServerReturning(html) {
server = http.createServer((request, response) => {
response.statusCode = 200;
response.end(html);
});
await server.listen(port);
}

describe('PendingXHR', () => {
describe('pendingXhrCount', () => {
it('returns 0 if no xhr pending count', async () => {
await startServerReturning(OK_NO_XHR);
const page = await browser.newPage();
const pendingXHR = new PendingXHR(page);
await page.goto(`http://localhost:${port}/no_xhr`);
await page.goto(`http://localhost:${port}/go`);
expect(pendingXHR.pendingXhrCount()).toEqual(0);
});

it('returns the xhr pending count', async () => {
await startServerReturning(OK_WITH_2_XHR);
const page = await browser.newPage();
const pendingXHR = new PendingXHR(page);
await page.goto(`http://localhost:${port}/with_infinite_xhr`);
await sleep(20);
await page.goto(`http://localhost:${port}/go`);
expect(pendingXHR.pendingXhrCount()).toEqual(2);
setTimeout(() => {
request1Resolver([200, 'first xhr finished']);
});
await sleep(10);
expect(pendingXHR.pendingXhrCount()).toEqual(1);
setTimeout(() => {
request2Resolver([200, 'second xhr finished']);
});
await sleep(10);
expect(pendingXHR.pendingXhrCount()).toEqual(0);
});
});

describe('waitForAllXhrFinished', async () => {
it('returns immediatly if no xhr pending count', async () => {
await startServerReturning(OK_NO_XHR);
const page = await browser.newPage();
const pendingXHR = new PendingXHR(page);
await page.goto(`http://localhost:${port}/no_xhr`);
await page.goto(`http://localhost:${port}/go`);
await pendingXHR.waitForAllXhrFinished();
});

it('waits for all xhr to end', async () => {
it('waits for 1 xhr to end', async () => {
await startServerReturning(OK_WITH_1_XHR);
const page = await browser.newPage();
const pendingXHR = new PendingXHR(page);
await page.goto(`http://localhost:${port}/with_xhr`);
await page.goto(`http://localhost:${port}/go`);
expect(pendingXHR.pendingXhrCount()).toEqual(1);
setTimeout(() => {
request1Resolver([200, '']);
});
await pendingXHR.waitForAllXhrFinished();
expect(pendingXHR.pendingXhrCount()).toEqual(0);
});

it('waits for 2 xhr to end', async () => {
await startServerReturning(OK_WITH_2_XHR);
const page = await browser.newPage();
const pendingXHR = new PendingXHR(page);
await page.goto(`http://localhost:${port}/go`);
expect(pendingXHR.pendingXhrCount()).toEqual(2);
setTimeout(() => {
request1Resolver([200, 'first xhr finished']);
});
setTimeout(() => {
request2Resolver([200, 'second xhr finished']);
}, 200);
await pendingXHR.waitForAllXhrFinished();
expect(pendingXHR.pendingXhrCount()).toEqual(0);
});

it('handle correctly failed xhr', async () => {
await startServerReturning(OK_WITH_1_XHR);
const page = await browser.newPage();
const pendingXHR = new PendingXHR(page);
await page.goto(`http://localhost:${port}/with_xhr_failing`);
await page.goto(`http://localhost:${port}/go`);
expect(pendingXHR.pendingXhrCount()).toEqual(1);
setTimeout(() => {
request1Resolver([500, 'boom']);
});
await pendingXHR.waitForAllXhrFinished();
expect(pendingXHR.pendingXhrCount()).toEqual(0);
});
Expand Down
29 changes: 13 additions & 16 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,35 +6,34 @@ class PendingXHR {
this.pendingXhrs = new Set();
this.finishedWithSuccessXhrs = new Set();
this.finishedWithErrorsXhrs = new Set();
this.promisees = [];
page.on('request', request => {
if (request.resourceType() === this.resourceType) {
this.pendingXhrs.add(request);
if (!this.promise) {
this.promise = new Promise(resolve => {
this.resolver = resolve;
});
}
this.promisees.push(
new Promise(resolve => {
request.resolver = resolve;
}),
);
}
});
page.on('requestfailed', request => {
if (request.resourceType() === this.resourceType) {
this.pendingXhrs.delete(request);
this.finishedWithErrorsXhrs.add(request);
if (this.resolver) {
this.resolver();
delete this.promise;
delete this.resolver;
if (request.resolver) {
request.resolver();
delete request.resolver;
}
}
});
page.on('requestfinished', request => {
if (request.resourceType() === this.resourceType) {
this.pendingXhrs.delete(request);
this.finishedWithSuccessXhrs.add(request);
if (this.resolver) {
this.resolver();
delete this.promise;
delete this.resolver;
if (request.resolver) {
request.resolver();
delete request.resolver;
}
}
});
Expand All @@ -44,9 +43,7 @@ class PendingXHR {
if (this.pendingXhrCount() === 0) {
return true;
}
if (this.promise) {
await this.promise;
}
await Promise.all(this.promisees);
}

pendingXhrCount() {
Expand Down