-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Multitab tests #9212
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
base: master
Are you sure you want to change the base?
Multitab tests #9212
Changes from all commits
5d2955a
96f2db3
dd7ac85
1412dc8
a117b74
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| 'use strict'; | ||
|
|
||
| const { spawn } = require('child_process'); | ||
| const devserver = require('./dev-server'); | ||
|
|
||
| const MOCHA_BIN = './node_modules/.bin/mocha'; | ||
| const MULTITAB_TESTS = 'tests/multitab'; | ||
| const TIMEOUT = '10000'; | ||
|
|
||
| devserver.start(() => { | ||
| let argv = ['-t', TIMEOUT, MULTITAB_TESTS]; | ||
| let mocha = spawn(MOCHA_BIN, argv, { stdio: 'inherit' }); | ||
| mocha.on('close', (status) => process.exit(status)); | ||
| }); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,42 @@ | ||
| 'use strict'; | ||
|
|
||
| const { assert } = require('chai'); | ||
| const UserAgent = require('./user_agent'); | ||
|
|
||
| describe('multi-tab concurrency', () => { | ||
| let agent, res; | ||
|
|
||
| beforeEach(async () => { | ||
| agent = await UserAgent.start(); | ||
| }); | ||
|
|
||
| afterEach(async () => { | ||
| await agent.stop(); | ||
| }); | ||
|
|
||
| async function checkInfo({ doc_count }) { | ||
| let info1 = await agent.eval(1, () => __pouch__.info()); | ||
| assert.equal(info1.doc_count, doc_count); | ||
|
|
||
| let info2 = await agent.eval(2, () => __pouch__.info()); | ||
| assert.deepEqual(info1, info2); | ||
| } | ||
|
|
||
| it('creates docs concurrently in two tabs', async () => { | ||
| res = await agent.eval(1, () => __pouch__.put({ _id: 'doc-1' })); | ||
| assert(res.ok); | ||
| await checkInfo({ doc_count: 1 }); | ||
|
|
||
| res = await agent.eval(2, () => __pouch__.put({ _id: 'doc-2' })); | ||
| assert(res.ok); | ||
| await checkInfo({ doc_count: 2 }); | ||
|
|
||
| res = await agent.eval(1, () => __pouch__.put({ _id: 'doc-3' })); | ||
| assert(res.ok); | ||
| await checkInfo({ doc_count: 3 }); // fails on indexeddb; pages have different info | ||
|
|
||
| res = await agent.eval(2, () => __pouch__.put({ _id: 'doc-4' })); | ||
| assert(res.ok); // fails on indexeddb | ||
| await checkInfo({ doc_count: 4 }); | ||
| }); | ||
| }); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| <!doctype html> | ||
| <html> | ||
| <head> | ||
| <title>Playwright shell</title> | ||
| <script src="/packages/node_modules/pouchdb/dist/pouchdb.min.js"></script> | ||
| <script src="/packages/node_modules/pouchdb/dist/pouchdb.indexeddb.min.js"></script> | ||
| </head> | ||
| <body></body> | ||
| </html> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,53 @@ | ||
| 'use strict'; | ||
|
|
||
| const playwright = require('playwright'); | ||
|
|
||
| const ADAPTERS = process.env.ADAPTERS || 'indexeddb'; | ||
| const CLIENT = process.env.CLIENT || 'firefox'; | ||
| const SHELL_URL = 'http://127.0.0.1:8000/tests/multitab/shell.html'; | ||
|
|
||
| class UserAgent { | ||
| static async start() { | ||
| let browser = await playwright[CLIENT].launch(); | ||
| let context = await browser.newContext(); | ||
| return new UserAgent(ADAPTERS, browser, context); | ||
| } | ||
|
|
||
| constructor(adapter, browser, context) { | ||
| this._adapter = adapter; | ||
| this._browser = browser; | ||
| this._context = context; | ||
| this._pages = new Map(); | ||
| } | ||
|
|
||
| async stop() { | ||
| await this._browser.close(); | ||
| } | ||
|
|
||
| async eval(pageId, fn) { | ||
| let page = await this._getPage(pageId); | ||
| return page.evaluate(fn); | ||
| } | ||
|
|
||
| _getPage(id) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "page" means "tab"? Maybe helpful to use consistent language?
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I was unsure about this. Everyone discussing these issues uses "tab" but Playwright uses "page". Strictly speaking, a "tab" is a particular UI for operating multiple pages, but it's not the only one. Colloquially I think "multi-tab" communicates "several pages operating concurrently" better than "multi-page" which to me sounds like a multi-step sequential workflow. |
||
| if (!this._pages.has(id)) { | ||
| this._pages.set(id, this._setupPage()); | ||
| } | ||
| return this._pages.get(id); | ||
| } | ||
|
|
||
| async _setupPage() { | ||
| let page = await this._context.newPage(); | ||
| await page.goto(SHELL_URL); | ||
|
|
||
| if (this._adapter === 'idb') { | ||
| await page.evaluate(() => window.__pouch__ = new PouchDB('testdb', { adapter: 'idb' })); | ||
| } else if (this._adapter === 'indexeddb') { | ||
| await page.evaluate(() => window.__pouch__ = new PouchDB('testdb', { adapter: 'indexeddb' })); | ||
| } | ||
|
|
||
| return page; | ||
| } | ||
| } | ||
|
|
||
| module.exports = UserAgent; | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could
window.__pouch__could be used instead of adding an extra constant here?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Omitting
window.from the test code was a readability win to me but I don't have a strong preference either way. Happy to change this if it's a big issue.