chore: implement a test runner on top of mocha (#8866)
* chore: implement a test runner on top of mocha This PR implements a test runner on top of mocha that performs multiple mocha runs as defined in TestSuites.json and compares the outcome of the runs against TestExpectations.json. This allows us to remove most of helpers from mocha-utils and be more flexible when defining the test configurations.
This commit is contained in:
parent
f02b926245
commit
d8830cbc55
22
.github/workflows/ci.yml
vendored
22
.github/workflows/ci.yml
vendored
@ -173,26 +173,12 @@ jobs:
|
||||
run: npm run build:dev
|
||||
- name: Test types
|
||||
run: npm run test:types
|
||||
# On Linux we run all Chrome tests without retries and Firefox tests with retries.
|
||||
- name: Run all Chrome tests (only on Linux)
|
||||
- name: Run all tests with xvfb
|
||||
if: ${{ matrix.spec.name == 'Linux' }}
|
||||
run: xvfb-run --auto-servernum npm run test:chrome
|
||||
- name: Run all Firefox tests (only on Linux)
|
||||
if: ${{ matrix.spec.name == 'Linux' }}
|
||||
uses: nick-invision/retry@v2
|
||||
with:
|
||||
command: xvfb-run --auto-servernum npm run test:firefox
|
||||
timeout_minutes: 20
|
||||
max_attempts: 3
|
||||
# On other platforms we only run chrome:headless tests and continue on Firefox errors.
|
||||
- name: Test Chrome Headless (not on Linux)
|
||||
id: test-chrome
|
||||
run: xvfb-run --auto-servernum npm run test
|
||||
- name: Run all tests without xvfb
|
||||
if: ${{ matrix.spec.name != 'Linux' }}
|
||||
run: npm run test:chrome:headless
|
||||
- name: Run all Firefox tests (not on Linux)
|
||||
if: ${{ matrix.spec.name != 'Linux' }}
|
||||
continue-on-error: true
|
||||
run: npm run test:firefox
|
||||
run: npm run test
|
||||
- name: Test bundling and installation
|
||||
if: ${{ matrix.spec.name == 'Linux' }}
|
||||
run: |
|
||||
|
@ -22,6 +22,6 @@ module.exports = {
|
||||
exit: !!process.env.CI,
|
||||
retries: process.env.CI ? 2 : 0,
|
||||
parallel: !!process.env.PARALLEL,
|
||||
timeout: 25 * 1000,
|
||||
timeout: 25_000,
|
||||
reporter: process.env.CI ? 'spec' : 'dot',
|
||||
};
|
||||
|
18
package-lock.json
generated
18
package-lock.json
generated
@ -80,7 +80,8 @@
|
||||
"text-diff": "1.0.1",
|
||||
"tsd": "0.22.0",
|
||||
"tsx": "3.8.2",
|
||||
"typescript": "4.7.4"
|
||||
"typescript": "4.7.4",
|
||||
"zod": "3.18.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.1.0"
|
||||
@ -7809,6 +7810,15 @@
|
||||
"optionalDependencies": {
|
||||
"commander": "^2.20.3"
|
||||
}
|
||||
},
|
||||
"node_modules/zod": {
|
||||
"version": "3.18.0",
|
||||
"resolved": "https://registry.npmjs.org/zod/-/zod-3.18.0.tgz",
|
||||
"integrity": "sha512-gwTm8RfUCe8l9rDwN5r2A17DkAa8Ez4Yl4yXqc5VqeGaXaJahzYYXbTwvhroZi0SNBqTwh/bKm2N0mpCzuw4bA==",
|
||||
"dev": true,
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/colinhacks"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
@ -13501,6 +13511,12 @@
|
||||
"lodash.isequal": "^4.5.0",
|
||||
"validator": "^13.7.0"
|
||||
}
|
||||
},
|
||||
"zod": {
|
||||
"version": "3.18.0",
|
||||
"resolved": "https://registry.npmjs.org/zod/-/zod-3.18.0.tgz",
|
||||
"integrity": "sha512-gwTm8RfUCe8l9rDwN5r2A17DkAa8Ez4Yl4yXqc5VqeGaXaJahzYYXbTwvhroZi0SNBqTwh/bKm2N0mpCzuw4bA==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
13
package.json
13
package.json
@ -27,14 +27,14 @@
|
||||
"node": ">=14.1.0"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "c8 --check-coverage --lines 93 run-s test:chrome:* test:firefox",
|
||||
"test": "cross-env MOZ_WEBRENDER=0 PUPPETEER_DEFERRED_PROMISE_DEBUG_TIMEOUT=20000 c8 --check-coverage --lines 93 node utils/mochaRunner/lib/main.js",
|
||||
"test:types": "tsd",
|
||||
"test:install": "scripts/test-install.sh",
|
||||
"test:firefox": "cross-env PUPPETEER_PRODUCT=firefox MOZ_WEBRENDER=0 PUPPETEER_DEFERRED_PROMISE_DEBUG_TIMEOUT=20000 mocha",
|
||||
"test:firefox": "npm run test -- --test-suite firefox-headless",
|
||||
"test:chrome": "run-s test:chrome:*",
|
||||
"test:chrome:headless": "cross-env HEADLESS=true PUPPETEER_DEFERRED_PROMISE_DEBUG_TIMEOUT=20000 mocha",
|
||||
"test:chrome:headless-chrome": "cross-env HEADLESS=chrome PUPPETEER_DEFERRED_PROMISE_DEBUG_TIMEOUT=20000 mocha",
|
||||
"test:chrome:headful": "cross-env HEADLESS=false PUPPETEER_DEFERRED_PROMISE_DEBUG_TIMEOUT=20000 mocha",
|
||||
"test:chrome:headless": "npm run test -- --test-suite chrome-headless",
|
||||
"test:chrome:headless-chrome": "npm run test -- --test-suite chrome-new-headless",
|
||||
"test:chrome:headful": "npm run test -- --test-suite chrome-headful",
|
||||
"prepublishOnly": "npm run build",
|
||||
"prepare": "node typescript-if-required.js && husky install",
|
||||
"lint": "run-s lint:prettier lint:eslint",
|
||||
@ -139,6 +139,7 @@
|
||||
"text-diff": "1.0.1",
|
||||
"tsd": "0.22.0",
|
||||
"tsx": "3.8.2",
|
||||
"typescript": "4.7.4"
|
||||
"typescript": "4.7.4",
|
||||
"zod": "3.18.0"
|
||||
}
|
||||
}
|
||||
|
1946
test/TestExpectations.json
Normal file
1946
test/TestExpectations.json
Normal file
File diff suppressed because it is too large
Load Diff
41
test/TestSuites.json
Normal file
41
test/TestSuites.json
Normal file
@ -0,0 +1,41 @@
|
||||
{
|
||||
"testSuites": [
|
||||
{
|
||||
"id": "chrome-headless",
|
||||
"platforms": ["linux", "win32", "darwin"],
|
||||
"parameters": ["chrome", "headless"]
|
||||
},
|
||||
{
|
||||
"id": "chrome-headful",
|
||||
"platforms": ["linux"],
|
||||
"parameters": ["chrome", "headful"]
|
||||
},
|
||||
{
|
||||
"id": "chrome-new-headless",
|
||||
"platforms": ["linux"],
|
||||
"parameters": ["chrome", "chrome-headless"]
|
||||
},
|
||||
{
|
||||
"id": "firefox-headless",
|
||||
"platforms": ["linux"],
|
||||
"parameters": ["firefox", "headless"]
|
||||
}
|
||||
],
|
||||
"parameterDefinitons": {
|
||||
"chrome": {
|
||||
"PUPPETEER_PRODUCT": "chrome"
|
||||
},
|
||||
"firefox": {
|
||||
"PUPPETEER_PRODUCT": "firefox"
|
||||
},
|
||||
"headless": {
|
||||
"HEADLESS": "true"
|
||||
},
|
||||
"headful": {
|
||||
"HEADLESS": "false"
|
||||
},
|
||||
"chrome-headless": {
|
||||
"HEADLESS": "chrome"
|
||||
}
|
||||
}
|
||||
}
|
@ -20,11 +20,11 @@ import {
|
||||
getTestState,
|
||||
setupTestBrowserHooks,
|
||||
setupTestPageAndContextHooks,
|
||||
describeChromeOnly,
|
||||
} from './mocha-utils.js';
|
||||
import {isErrorLike} from '../../lib/cjs/puppeteer/util/ErrorLike.js';
|
||||
import {it} from './mocha-utils.js';
|
||||
|
||||
describeChromeOnly('Target.createCDPSession', function () {
|
||||
describe('Target.createCDPSession', function () {
|
||||
setupTestBrowserHooks();
|
||||
setupTestPageAndContextHooks();
|
||||
|
||||
|
@ -17,6 +17,7 @@
|
||||
import {EventEmitter} from '../../lib/cjs/puppeteer/common/EventEmitter.js';
|
||||
import sinon from 'sinon';
|
||||
import expect from 'expect';
|
||||
import {it} from './mocha-utils.js';
|
||||
|
||||
describe('EventEmitter', () => {
|
||||
let emitter: EventEmitter;
|
||||
|
@ -14,8 +14,6 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {describeChromeOnly} from './mocha-utils.js';
|
||||
|
||||
import expect from 'expect';
|
||||
import {
|
||||
NetworkManager,
|
||||
@ -25,12 +23,13 @@ import {HTTPRequest} from '../../lib/cjs/puppeteer/common/HTTPRequest.js';
|
||||
import {EventEmitter} from '../../lib/cjs/puppeteer/common/EventEmitter.js';
|
||||
import {Frame} from '../../lib/cjs/puppeteer/common/Frame.js';
|
||||
import {HTTPResponse} from '../../lib/cjs/puppeteer/common/HTTPResponse.js';
|
||||
import {it} from './mocha-utils.js';
|
||||
|
||||
class MockCDPSession extends EventEmitter {
|
||||
async send(): Promise<any> {}
|
||||
}
|
||||
|
||||
describeChromeOnly('NetworkManager', () => {
|
||||
describe('NetworkManager', () => {
|
||||
it('should process extra info on multiple redirects', async () => {
|
||||
const mockCDPSession = new MockCDPSession();
|
||||
new NetworkManager(mockCDPSession, true, {
|
||||
|
@ -14,8 +14,9 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {describeChromeOnly, getTestState} from './mocha-utils'; // eslint-disable-line import/extensions
|
||||
import {getTestState} from './mocha-utils'; // eslint-disable-line import/extensions
|
||||
import utils from './utils.js';
|
||||
import {it} from './mocha-utils.js';
|
||||
|
||||
import expect from 'expect';
|
||||
|
||||
@ -24,7 +25,7 @@ import {
|
||||
BrowserContext,
|
||||
} from '../../lib/cjs/puppeteer/common/Browser.js';
|
||||
|
||||
describeChromeOnly('TargetManager', () => {
|
||||
describe('TargetManager', () => {
|
||||
/* We use a special browser for this test as we need the --site-per-process flag */
|
||||
let browser: Browser;
|
||||
let context: BrowserContext;
|
||||
|
@ -21,10 +21,10 @@ import {
|
||||
getTestState,
|
||||
setupTestBrowserHooks,
|
||||
setupTestPageAndContextHooks,
|
||||
describeFailsFirefox,
|
||||
} from './mocha-utils.js';
|
||||
import {it} from './mocha-utils.js';
|
||||
|
||||
describeFailsFirefox('Accessibility', function () {
|
||||
describe('Accessibility', function () {
|
||||
setupTestBrowserHooks();
|
||||
setupTestPageAndContextHooks();
|
||||
|
||||
@ -346,7 +346,7 @@ describeFailsFirefox('Accessibility', function () {
|
||||
});
|
||||
|
||||
// Firefox does not support contenteditable="plaintext-only".
|
||||
describeFailsFirefox('plaintext contenteditable', function () {
|
||||
describe('plaintext contenteditable', function () {
|
||||
it('plain text field with role should not have children', async () => {
|
||||
const {page} = getTestState();
|
||||
|
||||
|
@ -19,14 +19,14 @@ import {
|
||||
getTestState,
|
||||
setupTestBrowserHooks,
|
||||
setupTestPageAndContextHooks,
|
||||
describeChromeOnly,
|
||||
} from './mocha-utils.js';
|
||||
|
||||
import {ElementHandle} from '../../lib/cjs/puppeteer/common/ElementHandle.js';
|
||||
import utils from './utils.js';
|
||||
import assert from 'assert';
|
||||
import {it} from './mocha-utils.js';
|
||||
|
||||
describeChromeOnly('AriaQueryHandler', () => {
|
||||
describe('AriaQueryHandler', () => {
|
||||
setupTestBrowserHooks();
|
||||
setupTestPageAndContextHooks();
|
||||
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
import expect from 'expect';
|
||||
import {getTestState, setupTestBrowserHooks} from './mocha-utils.js';
|
||||
import {it} from './mocha-utils.js';
|
||||
|
||||
describe('Browser specs', function () {
|
||||
setupTestBrowserHooks();
|
||||
|
@ -15,12 +15,9 @@
|
||||
*/
|
||||
|
||||
import expect from 'expect';
|
||||
import {
|
||||
getTestState,
|
||||
itFailsFirefox,
|
||||
setupTestBrowserHooks,
|
||||
} from './mocha-utils.js';
|
||||
import {getTestState, setupTestBrowserHooks} from './mocha-utils.js';
|
||||
import {waitEvent} from './utils.js';
|
||||
import {it} from './mocha-utils.js';
|
||||
|
||||
describe('BrowserContext', function () {
|
||||
setupTestBrowserHooks();
|
||||
@ -60,7 +57,7 @@ describe('BrowserContext', function () {
|
||||
await context.close();
|
||||
expect((await browser.pages()).length).toBe(1);
|
||||
});
|
||||
itFailsFirefox('window.open should use parent tab context', async () => {
|
||||
it('window.open should use parent tab context', async () => {
|
||||
const {browser, server} = getTestState();
|
||||
|
||||
const context = await browser.createIncognitoBrowserContext();
|
||||
@ -75,7 +72,7 @@ describe('BrowserContext', function () {
|
||||
expect(popupTarget.browserContext()).toBe(context);
|
||||
await context.close();
|
||||
});
|
||||
itFailsFirefox('should fire target events', async () => {
|
||||
it('should fire target events', async () => {
|
||||
const {browser, server} = getTestState();
|
||||
|
||||
const context = await browser.createIncognitoBrowserContext();
|
||||
@ -99,7 +96,7 @@ describe('BrowserContext', function () {
|
||||
]);
|
||||
await context.close();
|
||||
});
|
||||
itFailsFirefox('should wait for a target', async () => {
|
||||
it('should wait for a target', async () => {
|
||||
const {browser, puppeteer, server} = getTestState();
|
||||
|
||||
const context = await browser.createIncognitoBrowserContext();
|
||||
@ -156,7 +153,7 @@ describe('BrowserContext', function () {
|
||||
await context.close();
|
||||
});
|
||||
|
||||
itFailsFirefox('should isolate localStorage and cookies', async () => {
|
||||
it('should isolate localStorage and cookies', async () => {
|
||||
const {browser, server} = getTestState();
|
||||
|
||||
// Create two incognito contexts.
|
||||
@ -216,7 +213,7 @@ describe('BrowserContext', function () {
|
||||
expect(browser.browserContexts().length).toBe(1);
|
||||
});
|
||||
|
||||
itFailsFirefox('should work across sessions', async () => {
|
||||
it('should work across sessions', async () => {
|
||||
const {browser, puppeteer} = getTestState();
|
||||
|
||||
expect(browser.browserContexts().length).toBe(1);
|
||||
|
@ -19,10 +19,10 @@ import {
|
||||
getTestState,
|
||||
setupTestBrowserHooks,
|
||||
setupTestPageAndContextHooks,
|
||||
describeChromeOnly,
|
||||
} from './mocha-utils.js';
|
||||
import {it} from './mocha-utils.js';
|
||||
|
||||
describeChromeOnly('Chromium-Specific Launcher tests', function () {
|
||||
describe('Chromium-Specific Launcher tests', function () {
|
||||
describe('Puppeteer.launch |browserURL| option', function () {
|
||||
it('should be able to connect using browserUrl, with and without trailing slash', async () => {
|
||||
const {defaultBrowserOptions, puppeteer} = getTestState();
|
||||
@ -138,7 +138,7 @@ describeChromeOnly('Chromium-Specific Launcher tests', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describeChromeOnly('Chromium-Specific Page Tests', function () {
|
||||
describe('Chromium-Specific Page Tests', function () {
|
||||
setupTestBrowserHooks();
|
||||
setupTestPageAndContextHooks();
|
||||
it('Page.setRequestInterception should work with intervention headers', async () => {
|
||||
|
@ -19,9 +19,9 @@ import {
|
||||
getTestState,
|
||||
setupTestPageAndContextHooks,
|
||||
setupTestBrowserHooks,
|
||||
itFailsFirefox,
|
||||
} from './mocha-utils.js';
|
||||
import utils from './utils.js';
|
||||
import {it} from './mocha-utils.js';
|
||||
|
||||
describe('Page.click', function () {
|
||||
setupTestBrowserHooks();
|
||||
@ -52,24 +52,21 @@ describe('Page.click', function () {
|
||||
})
|
||||
).toBe(42);
|
||||
});
|
||||
itFailsFirefox(
|
||||
'should click the button if window.Node is removed',
|
||||
async () => {
|
||||
const {page, server} = getTestState();
|
||||
it('should click the button if window.Node is removed', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
await page.goto(server.PREFIX + '/input/button.html');
|
||||
await page.goto(server.PREFIX + '/input/button.html');
|
||||
await page.evaluate(() => {
|
||||
// @ts-expect-error Expected.
|
||||
return delete window.Node;
|
||||
});
|
||||
await page.click('button');
|
||||
expect(
|
||||
await page.evaluate(() => {
|
||||
// @ts-expect-error Expected.
|
||||
return delete window.Node;
|
||||
});
|
||||
await page.click('button');
|
||||
expect(
|
||||
await page.evaluate(() => {
|
||||
return (globalThis as any).result;
|
||||
})
|
||||
).toBe('Clicked');
|
||||
}
|
||||
);
|
||||
return (globalThis as any).result;
|
||||
})
|
||||
).toBe('Clicked');
|
||||
});
|
||||
// @see https://github.com/puppeteer/puppeteer/issues/4281
|
||||
it('should click on a span with an inline element inside', async () => {
|
||||
const {page} = getTestState();
|
||||
@ -110,7 +107,7 @@ describe('Page.click', function () {
|
||||
})
|
||||
).toBe('Clicked');
|
||||
});
|
||||
itFailsFirefox('should click with disabled javascript', async () => {
|
||||
it('should click with disabled javascript', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
await page.setJavaScriptEnabled(false);
|
||||
@ -240,7 +237,7 @@ describe('Page.click', function () {
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
itFailsFirefox('should click on checkbox label and toggle', async () => {
|
||||
it('should click on checkbox label and toggle', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
await page.goto(server.PREFIX + '/input/checkbox.html');
|
||||
|
@ -19,8 +19,8 @@ import {
|
||||
getTestState,
|
||||
setupTestBrowserHooks,
|
||||
setupTestPageAndContextHooks,
|
||||
itFailsFirefox,
|
||||
} from './mocha-utils.js';
|
||||
import {it} from './mocha-utils.js';
|
||||
|
||||
describe('Cookie specs', () => {
|
||||
setupTestBrowserHooks();
|
||||
@ -128,7 +128,7 @@ describe('Cookie specs', () => {
|
||||
},
|
||||
]);
|
||||
});
|
||||
itFailsFirefox('should get cookies from multiple urls', async () => {
|
||||
it('should get cookies from multiple urls', async () => {
|
||||
const {page} = getTestState();
|
||||
await page.setCookie(
|
||||
{
|
||||
@ -184,7 +184,7 @@ describe('Cookie specs', () => {
|
||||
});
|
||||
});
|
||||
describe('Page.setCookie', function () {
|
||||
itFailsFirefox('should work', async () => {
|
||||
it('should work', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
@ -198,7 +198,7 @@ describe('Cookie specs', () => {
|
||||
})
|
||||
).toEqual('password=123456');
|
||||
});
|
||||
itFailsFirefox('should isolate cookies in browser contexts', async () => {
|
||||
it('should isolate cookies in browser contexts', async () => {
|
||||
const {page, server, browser} = getTestState();
|
||||
|
||||
const anotherContext = await browser.createIncognitoBrowserContext();
|
||||
@ -220,7 +220,7 @@ describe('Cookie specs', () => {
|
||||
expect(cookies2[0]!.value).toBe('page2value');
|
||||
await anotherContext.close();
|
||||
});
|
||||
itFailsFirefox('should set multiple cookies', async () => {
|
||||
it('should set multiple cookies', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
@ -257,7 +257,7 @@ describe('Cookie specs', () => {
|
||||
expect(cookies[0]!.session).toBe(true);
|
||||
expect(cookies[0]!.expires).toBe(-1);
|
||||
});
|
||||
itFailsFirefox('should set cookie with reasonable defaults', async () => {
|
||||
it('should set cookie with reasonable defaults', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
@ -288,7 +288,7 @@ describe('Cookie specs', () => {
|
||||
]
|
||||
);
|
||||
});
|
||||
itFailsFirefox('should set a cookie with a path', async () => {
|
||||
it('should set a cookie with a path', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
await page.goto(server.PREFIX + '/grid.html');
|
||||
@ -365,22 +365,19 @@ describe('Cookie specs', () => {
|
||||
'At least one of the url and domain needs to be specified'
|
||||
);
|
||||
});
|
||||
itFailsFirefox(
|
||||
'should default to setting secure cookie for HTTPS websites',
|
||||
async () => {
|
||||
const {page, server} = getTestState();
|
||||
it('should default to setting secure cookie for HTTPS websites', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
const SECURE_URL = 'https://example.com';
|
||||
await page.setCookie({
|
||||
url: SECURE_URL,
|
||||
name: 'foo',
|
||||
value: 'bar',
|
||||
});
|
||||
const [cookie] = await page.cookies(SECURE_URL);
|
||||
expect(cookie!.secure).toBe(true);
|
||||
}
|
||||
);
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
const SECURE_URL = 'https://example.com';
|
||||
await page.setCookie({
|
||||
url: SECURE_URL,
|
||||
name: 'foo',
|
||||
value: 'bar',
|
||||
});
|
||||
const [cookie] = await page.cookies(SECURE_URL);
|
||||
expect(cookie!.secure).toBe(true);
|
||||
});
|
||||
it('should be able to set unsecure cookie for HTTP website', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
@ -394,7 +391,7 @@ describe('Cookie specs', () => {
|
||||
const [cookie] = await page.cookies(HTTP_URL);
|
||||
expect(cookie!.secure).toBe(false);
|
||||
});
|
||||
itFailsFirefox('should set a cookie on a different domain', async () => {
|
||||
it('should set a cookie on a different domain', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
@ -422,7 +419,7 @@ describe('Cookie specs', () => {
|
||||
},
|
||||
]);
|
||||
});
|
||||
itFailsFirefox('should set cookies from a frame', async () => {
|
||||
it('should set cookies from a frame', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
await page.goto(server.PREFIX + '/grid.html');
|
||||
@ -482,71 +479,68 @@ describe('Cookie specs', () => {
|
||||
},
|
||||
]);
|
||||
});
|
||||
itFailsFirefox(
|
||||
'should set secure same-site cookies from a frame',
|
||||
async () => {
|
||||
const {httpsServer, puppeteer, defaultBrowserOptions} = getTestState();
|
||||
it('should set secure same-site cookies from a frame', async () => {
|
||||
const {httpsServer, puppeteer, defaultBrowserOptions} = getTestState();
|
||||
|
||||
const browser = await puppeteer.launch({
|
||||
...defaultBrowserOptions,
|
||||
ignoreHTTPSErrors: true,
|
||||
const browser = await puppeteer.launch({
|
||||
...defaultBrowserOptions,
|
||||
ignoreHTTPSErrors: true,
|
||||
});
|
||||
|
||||
const page = await browser.newPage();
|
||||
|
||||
try {
|
||||
await page.goto(httpsServer.PREFIX + '/grid.html');
|
||||
await page.evaluate(src => {
|
||||
let fulfill!: () => void;
|
||||
const promise = new Promise<void>(x => {
|
||||
return (fulfill = x);
|
||||
});
|
||||
const iframe = document.createElement('iframe');
|
||||
document.body.appendChild(iframe);
|
||||
iframe.onload = fulfill;
|
||||
iframe.src = src;
|
||||
return promise;
|
||||
}, httpsServer.CROSS_PROCESS_PREFIX);
|
||||
await page.setCookie({
|
||||
name: '127-same-site-cookie',
|
||||
value: 'best',
|
||||
url: httpsServer.CROSS_PROCESS_PREFIX,
|
||||
sameSite: 'None',
|
||||
});
|
||||
|
||||
const page = await browser.newPage();
|
||||
|
||||
try {
|
||||
await page.goto(httpsServer.PREFIX + '/grid.html');
|
||||
await page.evaluate(src => {
|
||||
let fulfill!: () => void;
|
||||
const promise = new Promise<void>(x => {
|
||||
return (fulfill = x);
|
||||
});
|
||||
const iframe = document.createElement('iframe');
|
||||
document.body.appendChild(iframe);
|
||||
iframe.onload = fulfill;
|
||||
iframe.src = src;
|
||||
return promise;
|
||||
}, httpsServer.CROSS_PROCESS_PREFIX);
|
||||
await page.setCookie({
|
||||
name: '127-same-site-cookie',
|
||||
value: 'best',
|
||||
url: httpsServer.CROSS_PROCESS_PREFIX,
|
||||
sameSite: 'None',
|
||||
});
|
||||
|
||||
expect(await page.frames()[1]!.evaluate('document.cookie')).toBe(
|
||||
'127-same-site-cookie=best'
|
||||
);
|
||||
expectCookieEquals(
|
||||
await page.cookies(httpsServer.CROSS_PROCESS_PREFIX),
|
||||
[
|
||||
{
|
||||
name: '127-same-site-cookie',
|
||||
value: 'best',
|
||||
domain: '127.0.0.1',
|
||||
path: '/',
|
||||
sameParty: false,
|
||||
expires: -1,
|
||||
size: 24,
|
||||
httpOnly: false,
|
||||
sameSite: 'None',
|
||||
secure: true,
|
||||
session: true,
|
||||
sourcePort: 443,
|
||||
sourceScheme: 'Secure',
|
||||
},
|
||||
]
|
||||
);
|
||||
} finally {
|
||||
await page.close();
|
||||
await browser.close();
|
||||
}
|
||||
expect(await page.frames()[1]!.evaluate('document.cookie')).toBe(
|
||||
'127-same-site-cookie=best'
|
||||
);
|
||||
expectCookieEquals(
|
||||
await page.cookies(httpsServer.CROSS_PROCESS_PREFIX),
|
||||
[
|
||||
{
|
||||
name: '127-same-site-cookie',
|
||||
value: 'best',
|
||||
domain: '127.0.0.1',
|
||||
path: '/',
|
||||
sameParty: false,
|
||||
expires: -1,
|
||||
size: 24,
|
||||
httpOnly: false,
|
||||
sameSite: 'None',
|
||||
secure: true,
|
||||
session: true,
|
||||
sourcePort: 443,
|
||||
sourceScheme: 'Secure',
|
||||
},
|
||||
]
|
||||
);
|
||||
} finally {
|
||||
await page.close();
|
||||
await browser.close();
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Page.deleteCookie', function () {
|
||||
itFailsFirefox('should work', async () => {
|
||||
it('should work', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
|
@ -19,11 +19,11 @@ import {
|
||||
getTestState,
|
||||
setupTestPageAndContextHooks,
|
||||
setupTestBrowserHooks,
|
||||
describeChromeOnly,
|
||||
} from './mocha-utils.js';
|
||||
import {it} from './mocha-utils.js';
|
||||
|
||||
describe('Coverage specs', function () {
|
||||
describeChromeOnly('JSCoverage', function () {
|
||||
describe('JSCoverage', function () {
|
||||
setupTestBrowserHooks();
|
||||
setupTestPageAndContextHooks();
|
||||
|
||||
@ -202,7 +202,7 @@ describe('Coverage specs', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describeChromeOnly('CSSCoverage', function () {
|
||||
describe('CSSCoverage', function () {
|
||||
setupTestBrowserHooks();
|
||||
setupTestPageAndContextHooks();
|
||||
|
||||
|
@ -19,8 +19,8 @@ import {
|
||||
getTestState,
|
||||
setupTestBrowserHooks,
|
||||
setupTestPageAndContextHooks,
|
||||
itFailsFirefox,
|
||||
} from './mocha-utils.js';
|
||||
import {it} from './mocha-utils.js';
|
||||
|
||||
describe('DefaultBrowserContext', function () {
|
||||
setupTestBrowserHooks();
|
||||
@ -48,7 +48,7 @@ describe('DefaultBrowserContext', function () {
|
||||
},
|
||||
]);
|
||||
});
|
||||
itFailsFirefox('page.setCookie() should work', async () => {
|
||||
it('page.setCookie() should work', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
@ -78,7 +78,7 @@ describe('DefaultBrowserContext', function () {
|
||||
},
|
||||
]);
|
||||
});
|
||||
itFailsFirefox('page.deleteCookie() should work', async () => {
|
||||
it('page.deleteCookie() should work', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
|
@ -20,8 +20,8 @@ import {
|
||||
getTestState,
|
||||
setupTestPageAndContextHooks,
|
||||
setupTestBrowserHooks,
|
||||
itFailsFirefox,
|
||||
} from './mocha-utils.js';
|
||||
import {it} from './mocha-utils.js';
|
||||
|
||||
describe('Page.Events.Dialog', function () {
|
||||
setupTestBrowserHooks();
|
||||
@ -46,7 +46,7 @@ describe('Page.Events.Dialog', function () {
|
||||
expect(dialog.message()).toBe('yo');
|
||||
});
|
||||
|
||||
itFailsFirefox('should allow accepting prompts', async () => {
|
||||
it('should allow accepting prompts', async () => {
|
||||
const {page} = getTestState();
|
||||
|
||||
const onDialog = sinon.stub().callsFake(dialog => {
|
||||
|
@ -19,10 +19,10 @@ import {
|
||||
getTestState,
|
||||
setupTestPageAndContextHooks,
|
||||
setupTestBrowserHooks,
|
||||
describeChromeOnly,
|
||||
} from './mocha-utils.js';
|
||||
import {it} from './mocha-utils.js';
|
||||
|
||||
describeChromeOnly('Input.drag', function () {
|
||||
describe('Input.drag', function () {
|
||||
setupTestBrowserHooks();
|
||||
setupTestPageAndContextHooks();
|
||||
it('should throw an exception if not enabled before usage', async () => {
|
||||
|
@ -18,12 +18,11 @@ import expect from 'expect';
|
||||
import sinon from 'sinon';
|
||||
import {ElementHandle} from '../../lib/cjs/puppeteer/common/ElementHandle.js';
|
||||
import {
|
||||
describeFailsFirefox,
|
||||
getTestState,
|
||||
itFailsFirefox,
|
||||
setupTestBrowserHooks,
|
||||
setupTestPageAndContextHooks,
|
||||
} from './mocha-utils.js';
|
||||
import {it} from './mocha-utils.js';
|
||||
|
||||
import utils from './utils.js';
|
||||
|
||||
@ -31,7 +30,7 @@ describe('ElementHandle specs', function () {
|
||||
setupTestBrowserHooks();
|
||||
setupTestPageAndContextHooks();
|
||||
|
||||
describeFailsFirefox('ElementHandle.boundingBox', function () {
|
||||
describe('ElementHandle.boundingBox', function () {
|
||||
it('should work', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
@ -96,7 +95,7 @@ describe('ElementHandle specs', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describeFailsFirefox('ElementHandle.boxModel', function () {
|
||||
describe('ElementHandle.boxModel', function () {
|
||||
it('should work', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
@ -162,7 +161,7 @@ describe('ElementHandle specs', function () {
|
||||
});
|
||||
|
||||
describe('ElementHandle.contentFrame', function () {
|
||||
itFailsFirefox('should work', async () => {
|
||||
it('should work', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
@ -175,7 +174,7 @@ describe('ElementHandle specs', function () {
|
||||
|
||||
describe('ElementHandle.click', function () {
|
||||
// See https://github.com/puppeteer/puppeteer/issues/7175
|
||||
itFailsFirefox('should work', async () => {
|
||||
it('should work', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
await page.goto(server.PREFIX + '/input/button.html');
|
||||
|
@ -20,9 +20,8 @@ import {
|
||||
getTestState,
|
||||
setupTestBrowserHooks,
|
||||
setupTestPageAndContextHooks,
|
||||
itFailsFirefox,
|
||||
describeFailsFirefox,
|
||||
} from './mocha-utils.js';
|
||||
import {it} from './mocha-utils.js';
|
||||
|
||||
describe('Emulation', () => {
|
||||
setupTestBrowserHooks();
|
||||
@ -132,7 +131,7 @@ describe('Emulation', () => {
|
||||
})
|
||||
).toBe(true);
|
||||
});
|
||||
itFailsFirefox('should support landscape emulation', async () => {
|
||||
it('should support landscape emulation', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
await page.goto(server.PREFIX + '/mobile.html');
|
||||
@ -173,7 +172,7 @@ describe('Emulation', () => {
|
||||
})
|
||||
).toContain('iPhone');
|
||||
});
|
||||
itFailsFirefox('should support clicking', async () => {
|
||||
it('should support clicking', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
await page.emulate(iPhone);
|
||||
@ -192,7 +191,7 @@ describe('Emulation', () => {
|
||||
});
|
||||
|
||||
describe('Page.emulateMediaType', function () {
|
||||
itFailsFirefox('should work', async () => {
|
||||
it('should work', async () => {
|
||||
const {page} = getTestState();
|
||||
|
||||
expect(
|
||||
@ -240,7 +239,7 @@ describe('Emulation', () => {
|
||||
});
|
||||
|
||||
describe('Page.emulateMediaFeatures', function () {
|
||||
itFailsFirefox('should work', async () => {
|
||||
it('should work', async () => {
|
||||
const {page} = getTestState();
|
||||
|
||||
await page.emulateMediaFeatures([
|
||||
@ -370,7 +369,7 @@ describe('Emulation', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describeFailsFirefox('Page.emulateTimezone', function () {
|
||||
describe('Page.emulateTimezone', function () {
|
||||
it('should work', async () => {
|
||||
const {page} = getTestState();
|
||||
|
||||
@ -425,7 +424,7 @@ describe('Emulation', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describeFailsFirefox('Page.emulateVisionDeficiency', function () {
|
||||
describe('Page.emulateVisionDeficiency', function () {
|
||||
it('should work', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
@ -489,7 +488,7 @@ describe('Emulation', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describeFailsFirefox('Page.emulateNetworkConditions', function () {
|
||||
describe('Page.emulateNetworkConditions', function () {
|
||||
it('should change navigator.connection.effectiveType', async () => {
|
||||
const {page, puppeteer} = getTestState();
|
||||
|
||||
@ -511,7 +510,7 @@ describe('Emulation', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describeFailsFirefox('Page.emulateCPUThrottling', function () {
|
||||
describe('Page.emulateCPUThrottling', function () {
|
||||
it('should change the CPU throttling rate successfully', async () => {
|
||||
const {page} = getTestState();
|
||||
|
||||
|
@ -20,9 +20,8 @@ import {
|
||||
getTestState,
|
||||
setupTestBrowserHooks,
|
||||
setupTestPageAndContextHooks,
|
||||
itFailsFirefox,
|
||||
describeFailsFirefox,
|
||||
} from './mocha-utils.js';
|
||||
import {it} from './mocha-utils.js';
|
||||
|
||||
const bigint = typeof BigInt !== 'undefined';
|
||||
|
||||
@ -115,18 +114,15 @@ describe('Evaluation specs', function () {
|
||||
await page.goto(server.PREFIX + '/global-var.html');
|
||||
expect(await page.evaluate('globalVar')).toBe(123);
|
||||
});
|
||||
itFailsFirefox(
|
||||
'should return undefined for objects with symbols',
|
||||
async () => {
|
||||
const {page} = getTestState();
|
||||
it('should return undefined for objects with symbols', async () => {
|
||||
const {page} = getTestState();
|
||||
|
||||
expect(
|
||||
await page.evaluate(() => {
|
||||
return [Symbol('foo4')];
|
||||
})
|
||||
).toBe(undefined);
|
||||
}
|
||||
);
|
||||
expect(
|
||||
await page.evaluate(() => {
|
||||
return [Symbol('foo4')];
|
||||
})
|
||||
).toBe(undefined);
|
||||
});
|
||||
it('should work with function shorthands', async () => {
|
||||
const {page} = getTestState();
|
||||
|
||||
@ -155,7 +151,7 @@ describe('Evaluation specs', function () {
|
||||
);
|
||||
expect(result).toBe(42);
|
||||
});
|
||||
itFailsFirefox('should throw when evaluation triggers reload', async () => {
|
||||
it('should throw when evaluation triggers reload', async () => {
|
||||
const {page} = getTestState();
|
||||
|
||||
let error!: Error;
|
||||
@ -189,7 +185,7 @@ describe('Evaluation specs', function () {
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
expect(await frameEvaluation).toBe(42);
|
||||
});
|
||||
itFailsFirefox('should work from-inside an exposed function', async () => {
|
||||
it('should work from-inside an exposed function', async () => {
|
||||
const {page} = getTestState();
|
||||
|
||||
// Setup inpage callback, which calls Page.evaluate
|
||||
@ -324,19 +320,16 @@ describe('Evaluation specs', function () {
|
||||
})
|
||||
).toEqual({});
|
||||
});
|
||||
itFailsFirefox(
|
||||
'should return undefined for non-serializable objects',
|
||||
async () => {
|
||||
const {page} = getTestState();
|
||||
it('should return undefined for non-serializable objects', async () => {
|
||||
const {page} = getTestState();
|
||||
|
||||
expect(
|
||||
await page.evaluate(() => {
|
||||
return window;
|
||||
})
|
||||
).toBe(undefined);
|
||||
}
|
||||
);
|
||||
itFailsFirefox('should fail for circular object', async () => {
|
||||
expect(
|
||||
await page.evaluate(() => {
|
||||
return window;
|
||||
})
|
||||
).toBe(undefined);
|
||||
});
|
||||
it('should fail for circular object', async () => {
|
||||
const {page} = getTestState();
|
||||
|
||||
const result = await page.evaluate(() => {
|
||||
@ -347,7 +340,7 @@ describe('Evaluation specs', function () {
|
||||
});
|
||||
expect(result).toBe(undefined);
|
||||
});
|
||||
itFailsFirefox('should be able to throw a tricky error', async () => {
|
||||
it('should be able to throw a tricky error', async () => {
|
||||
const {page} = getTestState();
|
||||
|
||||
const windowHandle = await page.evaluateHandle(() => {
|
||||
@ -410,28 +403,25 @@ describe('Evaluation specs', function () {
|
||||
});
|
||||
expect(error.message).toContain('JSHandle is disposed');
|
||||
});
|
||||
itFailsFirefox(
|
||||
'should throw if elementHandles are from other frames',
|
||||
async () => {
|
||||
const {page, server} = getTestState();
|
||||
it('should throw if elementHandles are from other frames', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
await utils.attachFrame(page, 'frame1', server.EMPTY_PAGE);
|
||||
const bodyHandle = await page.frames()[1]!.$('body');
|
||||
let error!: Error;
|
||||
await page
|
||||
.evaluate(body => {
|
||||
return body?.innerHTML;
|
||||
}, bodyHandle)
|
||||
.catch(error_ => {
|
||||
return (error = error_);
|
||||
});
|
||||
expect(error).toBeTruthy();
|
||||
expect(error.message).toContain(
|
||||
'JSHandles can be evaluated only in the context they were created'
|
||||
);
|
||||
}
|
||||
);
|
||||
itFailsFirefox('should simulate a user gesture', async () => {
|
||||
await utils.attachFrame(page, 'frame1', server.EMPTY_PAGE);
|
||||
const bodyHandle = await page.frames()[1]!.$('body');
|
||||
let error!: Error;
|
||||
await page
|
||||
.evaluate(body => {
|
||||
return body?.innerHTML;
|
||||
}, bodyHandle)
|
||||
.catch(error_ => {
|
||||
return (error = error_);
|
||||
});
|
||||
expect(error).toBeTruthy();
|
||||
expect(error.message).toContain(
|
||||
'JSHandles can be evaluated only in the context they were created'
|
||||
);
|
||||
});
|
||||
it('should simulate a user gesture', async () => {
|
||||
const {page} = getTestState();
|
||||
|
||||
const result = await page.evaluate(() => {
|
||||
@ -441,7 +431,7 @@ describe('Evaluation specs', function () {
|
||||
});
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
itFailsFirefox('should throw a nice error after a navigation', async () => {
|
||||
it('should throw a nice error after a navigation', async () => {
|
||||
const {page} = getTestState();
|
||||
|
||||
const executionContext = await page.mainFrame().executionContext();
|
||||
@ -461,19 +451,16 @@ describe('Evaluation specs', function () {
|
||||
});
|
||||
expect((error as Error).message).toContain('navigation');
|
||||
});
|
||||
itFailsFirefox(
|
||||
'should not throw an error when evaluation does a navigation',
|
||||
async () => {
|
||||
const {page, server} = getTestState();
|
||||
it('should not throw an error when evaluation does a navigation', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
await page.goto(server.PREFIX + '/one-style.html');
|
||||
const result = await page.evaluate(() => {
|
||||
(window as any).location = '/empty.html';
|
||||
return [42];
|
||||
});
|
||||
expect(result).toEqual([42]);
|
||||
}
|
||||
);
|
||||
await page.goto(server.PREFIX + '/one-style.html');
|
||||
const result = await page.evaluate(() => {
|
||||
(window as any).location = '/empty.html';
|
||||
return [42];
|
||||
});
|
||||
expect(result).toEqual([42]);
|
||||
});
|
||||
it('should transfer 100Mb of data from page to node.js', async function () {
|
||||
const {page} = getTestState();
|
||||
|
||||
@ -499,7 +486,7 @@ describe('Evaluation specs', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describeFailsFirefox('Page.evaluateOnNewDocument', function () {
|
||||
describe('Page.evaluateOnNewDocument', function () {
|
||||
it('should evaluate before anything else on the page', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
|
@ -17,12 +17,13 @@
|
||||
/* eslint-disable @typescript-eslint/no-var-requires */
|
||||
|
||||
import expect from 'expect';
|
||||
import {getTestState, itHeadlessOnly} from './mocha-utils.js';
|
||||
import {getTestState} from './mocha-utils.js';
|
||||
|
||||
import path from 'path';
|
||||
import {it} from './mocha-utils.js';
|
||||
|
||||
describe('Fixtures', function () {
|
||||
itHeadlessOnly('dumpio option should work with pipe option', async () => {
|
||||
it('dumpio option should work with pipe option', async () => {
|
||||
const {defaultBrowserOptions, puppeteerPath, headless} = getTestState();
|
||||
if (headless === 'chrome') {
|
||||
// This test only works in the old headless mode.
|
||||
|
@ -19,18 +19,18 @@ import {CDPSession} from '../../lib/cjs/puppeteer/common/Connection.js';
|
||||
import {Frame} from '../../lib/cjs/puppeteer/common/Frame.js';
|
||||
import {
|
||||
getTestState,
|
||||
itFailsFirefox,
|
||||
setupTestBrowserHooks,
|
||||
setupTestPageAndContextHooks,
|
||||
} from './mocha-utils.js';
|
||||
import utils, {dumpFrames} from './utils.js';
|
||||
import {it} from './mocha-utils.js';
|
||||
|
||||
describe('Frame specs', function () {
|
||||
setupTestBrowserHooks();
|
||||
setupTestPageAndContextHooks();
|
||||
|
||||
describe('Frame.executionContext', function () {
|
||||
itFailsFirefox('should work', async () => {
|
||||
it('should work', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
@ -80,7 +80,7 @@ describe('Frame specs', function () {
|
||||
});
|
||||
|
||||
describe('Frame.evaluate', function () {
|
||||
itFailsFirefox('should throw for detached frames', async () => {
|
||||
it('should throw for detached frames', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
const frame1 = (await utils.attachFrame(
|
||||
@ -126,7 +126,7 @@ describe('Frame specs', function () {
|
||||
});
|
||||
|
||||
describe('Frame Management', function () {
|
||||
itFailsFirefox('should handle nested frames', async () => {
|
||||
it('should handle nested frames', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
await page.goto(server.PREFIX + '/frames/nested-frames.html');
|
||||
@ -138,40 +138,37 @@ describe('Frame specs', function () {
|
||||
' http://localhost:<PORT>/frames/frame.html (aframe)',
|
||||
]);
|
||||
});
|
||||
itFailsFirefox(
|
||||
'should send events when frames are manipulated dynamically',
|
||||
async () => {
|
||||
const {page, server} = getTestState();
|
||||
it('should send events when frames are manipulated dynamically', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
// validate frameattached events
|
||||
const attachedFrames: Frame[] = [];
|
||||
page.on('frameattached', frame => {
|
||||
return attachedFrames.push(frame);
|
||||
});
|
||||
await utils.attachFrame(page, 'frame1', './assets/frame.html');
|
||||
expect(attachedFrames.length).toBe(1);
|
||||
expect(attachedFrames[0]!.url()).toContain('/assets/frame.html');
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
// validate frameattached events
|
||||
const attachedFrames: Frame[] = [];
|
||||
page.on('frameattached', frame => {
|
||||
return attachedFrames.push(frame);
|
||||
});
|
||||
await utils.attachFrame(page, 'frame1', './assets/frame.html');
|
||||
expect(attachedFrames.length).toBe(1);
|
||||
expect(attachedFrames[0]!.url()).toContain('/assets/frame.html');
|
||||
|
||||
// validate framenavigated events
|
||||
const navigatedFrames: Frame[] = [];
|
||||
page.on('framenavigated', frame => {
|
||||
return navigatedFrames.push(frame);
|
||||
});
|
||||
await utils.navigateFrame(page, 'frame1', './empty.html');
|
||||
expect(navigatedFrames.length).toBe(1);
|
||||
expect(navigatedFrames[0]!.url()).toBe(server.EMPTY_PAGE);
|
||||
// validate framenavigated events
|
||||
const navigatedFrames: Frame[] = [];
|
||||
page.on('framenavigated', frame => {
|
||||
return navigatedFrames.push(frame);
|
||||
});
|
||||
await utils.navigateFrame(page, 'frame1', './empty.html');
|
||||
expect(navigatedFrames.length).toBe(1);
|
||||
expect(navigatedFrames[0]!.url()).toBe(server.EMPTY_PAGE);
|
||||
|
||||
// validate framedetached events
|
||||
const detachedFrames: Frame[] = [];
|
||||
page.on('framedetached', frame => {
|
||||
return detachedFrames.push(frame);
|
||||
});
|
||||
await utils.detachFrame(page, 'frame1');
|
||||
expect(detachedFrames.length).toBe(1);
|
||||
expect(detachedFrames[0]!.isDetached()).toBe(true);
|
||||
}
|
||||
);
|
||||
// validate framedetached events
|
||||
const detachedFrames: Frame[] = [];
|
||||
page.on('framedetached', frame => {
|
||||
return detachedFrames.push(frame);
|
||||
});
|
||||
await utils.detachFrame(page, 'frame1');
|
||||
expect(detachedFrames.length).toBe(1);
|
||||
expect(detachedFrames[0]!.isDetached()).toBe(true);
|
||||
});
|
||||
it('should send "framenavigated" when navigating on anchor URLs', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
@ -259,7 +256,7 @@ describe('Frame specs', function () {
|
||||
expect(detachedFrames.length).toBe(4);
|
||||
expect(navigatedFrames.length).toBe(1);
|
||||
});
|
||||
itFailsFirefox('should report frame from-inside shadow DOM', async () => {
|
||||
it('should report frame from-inside shadow DOM', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
await page.goto(server.PREFIX + '/shadow.html');
|
||||
@ -274,7 +271,7 @@ describe('Frame specs', function () {
|
||||
expect(page.frames().length).toBe(2);
|
||||
expect(page.frames()[1]!.url()).toBe(server.EMPTY_PAGE);
|
||||
});
|
||||
itFailsFirefox('should report frame.name()', async () => {
|
||||
it('should report frame.name()', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
await utils.attachFrame(page, 'theFrameId', server.EMPTY_PAGE);
|
||||
@ -291,7 +288,7 @@ describe('Frame specs', function () {
|
||||
expect(page.frames()[1]!.name()).toBe('theFrameId');
|
||||
expect(page.frames()[2]!.name()).toBe('theFrameName');
|
||||
});
|
||||
itFailsFirefox('should report frame.parent()', async () => {
|
||||
it('should report frame.parent()', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
await utils.attachFrame(page, 'frame1', server.EMPTY_PAGE);
|
||||
@ -300,31 +297,24 @@ describe('Frame specs', function () {
|
||||
expect(page.frames()[1]!.parentFrame()).toBe(page.mainFrame());
|
||||
expect(page.frames()[2]!.parentFrame()).toBe(page.mainFrame());
|
||||
});
|
||||
itFailsFirefox(
|
||||
'should report different frame instance when frame re-attaches',
|
||||
async () => {
|
||||
const {page, server} = getTestState();
|
||||
it('should report different frame instance when frame re-attaches', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
const frame1 = await utils.attachFrame(
|
||||
page,
|
||||
'frame1',
|
||||
server.EMPTY_PAGE
|
||||
);
|
||||
await page.evaluate(() => {
|
||||
(globalThis as any).frame = document.querySelector('#frame1');
|
||||
(globalThis as any).frame.remove();
|
||||
});
|
||||
expect(frame1!.isDetached()).toBe(true);
|
||||
const [frame2] = await Promise.all([
|
||||
utils.waitEvent(page, 'frameattached'),
|
||||
page.evaluate(() => {
|
||||
return document.body.appendChild((globalThis as any).frame);
|
||||
}),
|
||||
]);
|
||||
expect(frame2.isDetached()).toBe(false);
|
||||
expect(frame1).not.toBe(frame2);
|
||||
}
|
||||
);
|
||||
const frame1 = await utils.attachFrame(page, 'frame1', server.EMPTY_PAGE);
|
||||
await page.evaluate(() => {
|
||||
(globalThis as any).frame = document.querySelector('#frame1');
|
||||
(globalThis as any).frame.remove();
|
||||
});
|
||||
expect(frame1!.isDetached()).toBe(true);
|
||||
const [frame2] = await Promise.all([
|
||||
utils.waitEvent(page, 'frameattached'),
|
||||
page.evaluate(() => {
|
||||
return document.body.appendChild((globalThis as any).frame);
|
||||
}),
|
||||
]);
|
||||
expect(frame2.isDetached()).toBe(false);
|
||||
expect(frame1).not.toBe(frame2);
|
||||
});
|
||||
it('should support url fragment', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
@ -335,7 +325,7 @@ describe('Frame specs', function () {
|
||||
server.PREFIX + '/frames/frame.html?param=value#fragment'
|
||||
);
|
||||
});
|
||||
itFailsFirefox('should support lazy frames', async () => {
|
||||
it('should support lazy frames', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
await page.setViewport({width: 1000, height: 1000});
|
||||
|
@ -24,11 +24,8 @@ import {
|
||||
PuppeteerLaunchOptions,
|
||||
PuppeteerNode,
|
||||
} from '../../lib/cjs/puppeteer/node/Puppeteer.js';
|
||||
import {
|
||||
describeChromeOnly,
|
||||
getTestState,
|
||||
itFailsWindows,
|
||||
} from './mocha-utils.js';
|
||||
import {getTestState} from './mocha-utils.js';
|
||||
import {it} from './mocha-utils.js';
|
||||
|
||||
const rmAsync = promisify(rimraf);
|
||||
const mkdtempAsync = promisify(fs.mkdtemp);
|
||||
@ -44,7 +41,7 @@ const serviceWorkerExtensionPath = path.join(
|
||||
'extension'
|
||||
);
|
||||
|
||||
describeChromeOnly('headful tests', function () {
|
||||
describe('headful tests', function () {
|
||||
/* These tests fire up an actual browser so let's
|
||||
* allow a higher timeout
|
||||
*/
|
||||
@ -214,41 +211,38 @@ describeChromeOnly('headful tests', function () {
|
||||
expect(pages).toEqual(['about:blank']);
|
||||
await browser.close();
|
||||
});
|
||||
itFailsWindows(
|
||||
'headless should be able to read cookies written by headful',
|
||||
async () => {
|
||||
/* Needs investigation into why but this fails consistently on Windows CI. */
|
||||
const {server, puppeteer} = getTestState();
|
||||
it('headless should be able to read cookies written by headful', async () => {
|
||||
/* Needs investigation into why but this fails consistently on Windows CI. */
|
||||
const {server, puppeteer} = getTestState();
|
||||
|
||||
const userDataDir = await mkdtempAsync(TMP_FOLDER);
|
||||
// Write a cookie in headful chrome
|
||||
const headfulBrowser = await launchBrowser(
|
||||
puppeteer,
|
||||
Object.assign({userDataDir}, headfulOptions)
|
||||
);
|
||||
const headfulPage = await headfulBrowser.newPage();
|
||||
await headfulPage.goto(server.EMPTY_PAGE);
|
||||
await headfulPage.evaluate(() => {
|
||||
return (document.cookie =
|
||||
'foo=true; expires=Fri, 31 Dec 9999 23:59:59 GMT');
|
||||
});
|
||||
await headfulBrowser.close();
|
||||
// Read the cookie from headless chrome
|
||||
const headlessBrowser = await launchBrowser(
|
||||
puppeteer,
|
||||
Object.assign({userDataDir}, headlessOptions)
|
||||
);
|
||||
const headlessPage = await headlessBrowser.newPage();
|
||||
await headlessPage.goto(server.EMPTY_PAGE);
|
||||
const cookie = await headlessPage.evaluate(() => {
|
||||
return document.cookie;
|
||||
});
|
||||
await headlessBrowser.close();
|
||||
// This might throw. See https://github.com/puppeteer/puppeteer/issues/2778
|
||||
await rmAsync(userDataDir).catch(() => {});
|
||||
expect(cookie).toBe('foo=true');
|
||||
}
|
||||
);
|
||||
const userDataDir = await mkdtempAsync(TMP_FOLDER);
|
||||
// Write a cookie in headful chrome
|
||||
const headfulBrowser = await launchBrowser(
|
||||
puppeteer,
|
||||
Object.assign({userDataDir}, headfulOptions)
|
||||
);
|
||||
const headfulPage = await headfulBrowser.newPage();
|
||||
await headfulPage.goto(server.EMPTY_PAGE);
|
||||
await headfulPage.evaluate(() => {
|
||||
return (document.cookie =
|
||||
'foo=true; expires=Fri, 31 Dec 9999 23:59:59 GMT');
|
||||
});
|
||||
await headfulBrowser.close();
|
||||
// Read the cookie from headless chrome
|
||||
const headlessBrowser = await launchBrowser(
|
||||
puppeteer,
|
||||
Object.assign({userDataDir}, headlessOptions)
|
||||
);
|
||||
const headlessPage = await headlessBrowser.newPage();
|
||||
await headlessPage.goto(server.EMPTY_PAGE);
|
||||
const cookie = await headlessPage.evaluate(() => {
|
||||
return document.cookie;
|
||||
});
|
||||
await headlessBrowser.close();
|
||||
// This might throw. See https://github.com/puppeteer/puppeteer/issues/2778
|
||||
await rmAsync(userDataDir).catch(() => {});
|
||||
expect(cookie).toBe('foo=true');
|
||||
});
|
||||
// TODO: Support OOOPIF. @see https://github.com/puppeteer/puppeteer/issues/2548
|
||||
xit('OOPIF: should report google.com frame', async () => {
|
||||
const {server, puppeteer} = getTestState();
|
||||
|
@ -20,10 +20,10 @@ import {
|
||||
getTestState,
|
||||
setupTestBrowserHooks,
|
||||
setupTestPageAndContextHooks,
|
||||
describeFailsFirefox,
|
||||
} from './mocha-utils.js';
|
||||
import {it} from './mocha-utils.js';
|
||||
|
||||
describeFailsFirefox('Emulate idle state', () => {
|
||||
describe('Emulate idle state', () => {
|
||||
setupTestBrowserHooks();
|
||||
setupTestPageAndContextHooks();
|
||||
|
||||
|
@ -22,11 +22,8 @@ import {
|
||||
} from '../../lib/cjs/puppeteer/common/Browser.js';
|
||||
import {Page} from '../../lib/cjs/puppeteer/common/Page.js';
|
||||
import {HTTPResponse} from '../../lib/cjs/puppeteer/common/HTTPResponse.js';
|
||||
import {
|
||||
getTestState,
|
||||
describeFailsFirefox,
|
||||
itFailsFirefox,
|
||||
} from './mocha-utils.js';
|
||||
import {getTestState} from './mocha-utils.js';
|
||||
import {it} from './mocha-utils.js';
|
||||
|
||||
describe('ignoreHTTPSErrors', function () {
|
||||
/* Note that this test creates its own browser rather than use
|
||||
@ -59,7 +56,7 @@ describe('ignoreHTTPSErrors', function () {
|
||||
await context.close();
|
||||
});
|
||||
|
||||
describeFailsFirefox('Response.securityDetails', function () {
|
||||
describe('Response.securityDetails', function () {
|
||||
it('should work', async () => {
|
||||
const {httpsServer} = getTestState();
|
||||
|
||||
@ -119,7 +116,7 @@ describe('ignoreHTTPSErrors', function () {
|
||||
expect(error).toBeUndefined();
|
||||
expect(response.ok()).toBe(true);
|
||||
});
|
||||
itFailsFirefox('should work with request interception', async () => {
|
||||
it('should work with request interception', async () => {
|
||||
const {httpsServer} = getTestState();
|
||||
|
||||
await page.setRequestInterception(true);
|
||||
@ -129,7 +126,7 @@ describe('ignoreHTTPSErrors', function () {
|
||||
const response = (await page.goto(httpsServer.EMPTY_PAGE))!;
|
||||
expect(response.status()).toBe(200);
|
||||
});
|
||||
itFailsFirefox('should work with mixed content', async () => {
|
||||
it('should work with mixed content', async () => {
|
||||
const {server, httpsServer} = getTestState();
|
||||
|
||||
httpsServer.setRoute('/mixedcontent.html', (_req, res) => {
|
||||
|
@ -20,8 +20,8 @@ import {
|
||||
getTestState,
|
||||
setupTestBrowserHooks,
|
||||
setupTestPageAndContextHooks,
|
||||
describeFailsFirefox,
|
||||
} from './mocha-utils.js';
|
||||
import {it} from './mocha-utils.js';
|
||||
|
||||
const FILE_TO_UPLOAD = path.join(__dirname, '/../assets/file-to-upload.txt');
|
||||
|
||||
@ -29,7 +29,7 @@ describe('input tests', function () {
|
||||
setupTestBrowserHooks();
|
||||
setupTestPageAndContextHooks();
|
||||
|
||||
describeFailsFirefox('input', function () {
|
||||
describe('input', function () {
|
||||
it('should upload the file', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
@ -76,7 +76,7 @@ describe('input tests', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describeFailsFirefox('Page.waitForFileChooser', function () {
|
||||
describe('Page.waitForFileChooser', function () {
|
||||
it('should work when file input is attached to DOM', async () => {
|
||||
const {page} = getTestState();
|
||||
|
||||
@ -159,7 +159,7 @@ describe('input tests', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describeFailsFirefox('FileChooser.accept', function () {
|
||||
describe('FileChooser.accept', function () {
|
||||
it('should accept single file', async () => {
|
||||
const {page} = getTestState();
|
||||
|
||||
@ -325,7 +325,7 @@ describe('input tests', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describeFailsFirefox('FileChooser.cancel', function () {
|
||||
describe('FileChooser.cancel', function () {
|
||||
it('should cancel dialog', async () => {
|
||||
const {page} = getTestState();
|
||||
|
||||
@ -373,7 +373,7 @@ describe('input tests', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describeFailsFirefox('FileChooser.isMultiple', () => {
|
||||
describe('FileChooser.isMultiple', () => {
|
||||
it('should work for single file pick', async () => {
|
||||
const {page} = getTestState();
|
||||
|
||||
|
@ -17,11 +17,11 @@
|
||||
import expect from 'expect';
|
||||
import {
|
||||
getTestState,
|
||||
itFailsFirefox,
|
||||
setupTestBrowserHooks,
|
||||
setupTestPageAndContextHooks,
|
||||
shortWaitForArrayToHaveAtLeastNElements,
|
||||
} from './mocha-utils.js';
|
||||
import {it} from './mocha-utils.js';
|
||||
|
||||
describe('JSHandle', function () {
|
||||
setupTestBrowserHooks();
|
||||
@ -159,7 +159,7 @@ describe('JSHandle', function () {
|
||||
expect(await bHandle.jsonValue()).toEqual(undefined);
|
||||
});
|
||||
|
||||
itFailsFirefox('should not work with dates', async () => {
|
||||
it('should not work with dates', async () => {
|
||||
const {page} = getTestState();
|
||||
|
||||
const dateHandle = await page.evaluateHandle(() => {
|
||||
@ -409,7 +409,7 @@ describe('JSHandle', function () {
|
||||
});
|
||||
|
||||
describe('JSHandle.click', function () {
|
||||
itFailsFirefox('should work', async () => {
|
||||
it('should work', async () => {
|
||||
const {page} = getTestState();
|
||||
|
||||
const clicks: Array<[x: number, y: number]> = [];
|
||||
|
@ -21,9 +21,9 @@ import {
|
||||
getTestState,
|
||||
setupTestBrowserHooks,
|
||||
setupTestPageAndContextHooks,
|
||||
itFailsFirefox,
|
||||
} from './mocha-utils.js';
|
||||
import {KeyInput} from '../../lib/cjs/puppeteer/common/USKeyboardLayout.js';
|
||||
import {it} from './mocha-utils.js';
|
||||
|
||||
describe('Keyboard', function () {
|
||||
setupTestBrowserHooks();
|
||||
@ -45,7 +45,7 @@ describe('Keyboard', function () {
|
||||
})
|
||||
).toBe(text);
|
||||
});
|
||||
itFailsFirefox('should press the metaKey', async () => {
|
||||
it('should press the metaKey', async () => {
|
||||
const {page, isFirefox} = getTestState();
|
||||
|
||||
await page.evaluate(() => {
|
||||
@ -120,22 +120,19 @@ describe('Keyboard', function () {
|
||||
})
|
||||
).toBe('a');
|
||||
});
|
||||
itFailsFirefox(
|
||||
'ElementHandle.press should support |text| option',
|
||||
async () => {
|
||||
const {page, server} = getTestState();
|
||||
it('ElementHandle.press should support |text| option', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
await page.goto(server.PREFIX + '/input/textarea.html');
|
||||
const textarea = (await page.$('textarea'))!;
|
||||
await textarea.press('a', {text: 'ё'});
|
||||
expect(
|
||||
await page.evaluate(() => {
|
||||
return document.querySelector('textarea')!.value;
|
||||
})
|
||||
).toBe('ё');
|
||||
}
|
||||
);
|
||||
itFailsFirefox('should send a character with sendCharacter', async () => {
|
||||
await page.goto(server.PREFIX + '/input/textarea.html');
|
||||
const textarea = (await page.$('textarea'))!;
|
||||
await textarea.press('a', {text: 'ё'});
|
||||
expect(
|
||||
await page.evaluate(() => {
|
||||
return document.querySelector('textarea')!.value;
|
||||
})
|
||||
).toBe('ё');
|
||||
});
|
||||
it('should send a character with sendCharacter', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
await page.goto(server.PREFIX + '/input/textarea.html');
|
||||
@ -162,7 +159,7 @@ describe('Keyboard', function () {
|
||||
})
|
||||
).toBe('嗨a');
|
||||
});
|
||||
itFailsFirefox('should report shiftKey', async () => {
|
||||
it('should report shiftKey', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
await page.goto(server.PREFIX + '/input/keyboard.html');
|
||||
@ -353,7 +350,7 @@ describe('Keyboard', function () {
|
||||
})
|
||||
).toBe('He Wrd!');
|
||||
});
|
||||
itFailsFirefox('should specify repeat property', async () => {
|
||||
it('should specify repeat property', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
await page.goto(server.PREFIX + '/input/textarea.html');
|
||||
@ -401,7 +398,7 @@ describe('Keyboard', function () {
|
||||
})
|
||||
).toBe(false);
|
||||
});
|
||||
itFailsFirefox('should type all kinds of characters', async () => {
|
||||
it('should type all kinds of characters', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
await page.goto(server.PREFIX + '/input/textarea.html');
|
||||
@ -410,7 +407,7 @@ describe('Keyboard', function () {
|
||||
await page.keyboard.type(text);
|
||||
expect(await page.evaluate('result')).toBe(text);
|
||||
});
|
||||
itFailsFirefox('should specify location', async () => {
|
||||
it('should specify location', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
await page.goto(server.PREFIX + '/input/textarea.html');
|
||||
@ -460,7 +457,7 @@ describe('Keyboard', function () {
|
||||
});
|
||||
expect(error && error.message).toBe('Unknown key: "😊"');
|
||||
});
|
||||
itFailsFirefox('should type emoji', async () => {
|
||||
it('should type emoji', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
await page.goto(server.PREFIX + '/input/textarea.html');
|
||||
@ -471,7 +468,7 @@ describe('Keyboard', function () {
|
||||
})
|
||||
).toBe('👹 Tokyo street Japan 🇯🇵');
|
||||
});
|
||||
itFailsFirefox('should type emoji into an iframe', async () => {
|
||||
it('should type emoji into an iframe', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
@ -489,7 +486,7 @@ describe('Keyboard', function () {
|
||||
})
|
||||
).toBe('👹 Tokyo street Japan 🇯🇵');
|
||||
});
|
||||
itFailsFirefox('should press the meta key', async () => {
|
||||
it('should press the meta key', async () => {
|
||||
const {page, isFirefox} = getTestState();
|
||||
|
||||
await page.evaluate(() => {
|
||||
|
@ -24,14 +24,9 @@ import {TLSSocket} from 'tls';
|
||||
import {promisify} from 'util';
|
||||
import {Page} from '../../lib/cjs/puppeteer/common/Page.js';
|
||||
import {Product} from '../../lib/cjs/puppeteer/common/Product.js';
|
||||
import {
|
||||
getTestState,
|
||||
itChromeOnly,
|
||||
itFailsFirefox,
|
||||
itFirefoxOnly,
|
||||
itOnlyRegularInstall,
|
||||
} from './mocha-utils.js';
|
||||
import {getTestState, itOnlyRegularInstall} from './mocha-utils.js';
|
||||
import utils from './utils.js';
|
||||
import {it} from './mocha-utils.js';
|
||||
|
||||
const mkdtempAsync = promisify(fs.mkdtemp);
|
||||
const readFileAsync = promisify(fs.readFile);
|
||||
@ -251,7 +246,7 @@ describe('Launcher specs', function () {
|
||||
// This might throw. See https://github.com/puppeteer/puppeteer/issues/2778
|
||||
await rmAsync(userDataDir).catch(() => {});
|
||||
});
|
||||
itChromeOnly('tmp profile should be cleaned up', async () => {
|
||||
it('tmp profile should be cleaned up', async () => {
|
||||
const {defaultBrowserOptions, puppeteer} = getTestState();
|
||||
|
||||
// Set a custom test tmp dir so that we can validate that
|
||||
@ -280,7 +275,7 @@ describe('Launcher specs', function () {
|
||||
// Restore env var
|
||||
process.env['PUPPETEER_TMP_DIR'] = '';
|
||||
});
|
||||
itFirefoxOnly('userDataDir option restores preferences', async () => {
|
||||
it('userDataDir option restores preferences', async () => {
|
||||
const {defaultBrowserOptions, puppeteer} = getTestState();
|
||||
|
||||
const userDataDir = await mkdtempAsync(TMP_FOLDER);
|
||||
@ -326,7 +321,7 @@ describe('Launcher specs', function () {
|
||||
// This might throw. See https://github.com/puppeteer/puppeteer/issues/2778
|
||||
await rmAsync(userDataDir).catch(() => {});
|
||||
});
|
||||
itChromeOnly('userDataDir argument with non-existent dir', async () => {
|
||||
it('userDataDir argument with non-existent dir', async () => {
|
||||
const {isChrome, puppeteer, defaultBrowserOptions} = getTestState();
|
||||
|
||||
const userDataDir = await mkdtempAsync(TMP_FOLDER);
|
||||
@ -460,49 +455,43 @@ describe('Launcher specs', function () {
|
||||
await page.close();
|
||||
await browser.close();
|
||||
});
|
||||
itChromeOnly(
|
||||
'should filter out ignored default arguments in Chrome',
|
||||
async () => {
|
||||
const {defaultBrowserOptions, puppeteer} = getTestState();
|
||||
// Make sure we launch with `--enable-automation` by default.
|
||||
const defaultArgs = puppeteer.defaultArgs();
|
||||
const browser = await puppeteer.launch(
|
||||
Object.assign({}, defaultBrowserOptions, {
|
||||
// Ignore first and third default argument.
|
||||
ignoreDefaultArgs: [defaultArgs[0]!, defaultArgs[2]],
|
||||
})
|
||||
);
|
||||
const spawnargs = browser.process()!.spawnargs;
|
||||
if (!spawnargs) {
|
||||
throw new Error('spawnargs not present');
|
||||
}
|
||||
expect(spawnargs.indexOf(defaultArgs[0]!)).toBe(-1);
|
||||
expect(spawnargs.indexOf(defaultArgs[1]!)).not.toBe(-1);
|
||||
expect(spawnargs.indexOf(defaultArgs[2]!)).toBe(-1);
|
||||
await browser.close();
|
||||
it('should filter out ignored default arguments in Chrome', async () => {
|
||||
const {defaultBrowserOptions, puppeteer} = getTestState();
|
||||
// Make sure we launch with `--enable-automation` by default.
|
||||
const defaultArgs = puppeteer.defaultArgs();
|
||||
const browser = await puppeteer.launch(
|
||||
Object.assign({}, defaultBrowserOptions, {
|
||||
// Ignore first and third default argument.
|
||||
ignoreDefaultArgs: [defaultArgs[0]!, defaultArgs[2]],
|
||||
})
|
||||
);
|
||||
const spawnargs = browser.process()!.spawnargs;
|
||||
if (!spawnargs) {
|
||||
throw new Error('spawnargs not present');
|
||||
}
|
||||
);
|
||||
itFirefoxOnly(
|
||||
'should filter out ignored default argument in Firefox',
|
||||
async () => {
|
||||
const {defaultBrowserOptions, puppeteer} = getTestState();
|
||||
expect(spawnargs.indexOf(defaultArgs[0]!)).toBe(-1);
|
||||
expect(spawnargs.indexOf(defaultArgs[1]!)).not.toBe(-1);
|
||||
expect(spawnargs.indexOf(defaultArgs[2]!)).toBe(-1);
|
||||
await browser.close();
|
||||
});
|
||||
it('should filter out ignored default argument in Firefox', async () => {
|
||||
const {defaultBrowserOptions, puppeteer} = getTestState();
|
||||
|
||||
const defaultArgs = puppeteer.defaultArgs();
|
||||
const browser = await puppeteer.launch(
|
||||
Object.assign({}, defaultBrowserOptions, {
|
||||
// Only the first argument is fixed, others are optional.
|
||||
ignoreDefaultArgs: [defaultArgs[0]!],
|
||||
})
|
||||
);
|
||||
const spawnargs = browser.process()!.spawnargs;
|
||||
if (!spawnargs) {
|
||||
throw new Error('spawnargs not present');
|
||||
}
|
||||
expect(spawnargs.indexOf(defaultArgs[0]!)).toBe(-1);
|
||||
expect(spawnargs.indexOf(defaultArgs[1]!)).not.toBe(-1);
|
||||
await browser.close();
|
||||
const defaultArgs = puppeteer.defaultArgs();
|
||||
const browser = await puppeteer.launch(
|
||||
Object.assign({}, defaultBrowserOptions, {
|
||||
// Only the first argument is fixed, others are optional.
|
||||
ignoreDefaultArgs: [defaultArgs[0]!],
|
||||
})
|
||||
);
|
||||
const spawnargs = browser.process()!.spawnargs;
|
||||
if (!spawnargs) {
|
||||
throw new Error('spawnargs not present');
|
||||
}
|
||||
);
|
||||
expect(spawnargs.indexOf(defaultArgs[0]!)).toBe(-1);
|
||||
expect(spawnargs.indexOf(defaultArgs[1]!)).not.toBe(-1);
|
||||
await browser.close();
|
||||
});
|
||||
it('should have default URL when launching browser', async function () {
|
||||
const {defaultBrowserOptions, puppeteer} = getTestState();
|
||||
const browser = await puppeteer.launch(defaultBrowserOptions);
|
||||
@ -512,24 +501,21 @@ describe('Launcher specs', function () {
|
||||
expect(pages).toEqual(['about:blank']);
|
||||
await browser.close();
|
||||
});
|
||||
itFailsFirefox(
|
||||
'should have custom URL when launching browser',
|
||||
async () => {
|
||||
const {server, puppeteer, defaultBrowserOptions} = getTestState();
|
||||
it('should have custom URL when launching browser', async () => {
|
||||
const {server, puppeteer, defaultBrowserOptions} = getTestState();
|
||||
|
||||
const options = Object.assign({}, defaultBrowserOptions);
|
||||
options.args = [server.EMPTY_PAGE].concat(options.args || []);
|
||||
const browser = await puppeteer.launch(options);
|
||||
const pages = await browser.pages();
|
||||
expect(pages.length).toBe(1);
|
||||
const page = pages[0]!;
|
||||
if (page.url() !== server.EMPTY_PAGE) {
|
||||
await page.waitForNavigation();
|
||||
}
|
||||
expect(page.url()).toBe(server.EMPTY_PAGE);
|
||||
await browser.close();
|
||||
const options = Object.assign({}, defaultBrowserOptions);
|
||||
options.args = [server.EMPTY_PAGE].concat(options.args || []);
|
||||
const browser = await puppeteer.launch(options);
|
||||
const pages = await browser.pages();
|
||||
expect(pages.length).toBe(1);
|
||||
const page = pages[0]!;
|
||||
if (page.url() !== server.EMPTY_PAGE) {
|
||||
await page.waitForNavigation();
|
||||
}
|
||||
);
|
||||
expect(page.url()).toBe(server.EMPTY_PAGE);
|
||||
await browser.close();
|
||||
});
|
||||
it('should pass the timeout parameter to browser.waitForTarget', async () => {
|
||||
const {puppeteer, defaultBrowserOptions} = getTestState();
|
||||
const options = Object.assign({}, defaultBrowserOptions, {
|
||||
@ -615,24 +601,21 @@ describe('Launcher specs', function () {
|
||||
});
|
||||
expect(error.message).toContain('either pipe or debugging port');
|
||||
});
|
||||
itChromeOnly(
|
||||
'should launch Chrome properly with --no-startup-window and waitForInitialPage=false',
|
||||
async () => {
|
||||
const {defaultBrowserOptions, puppeteer} = getTestState();
|
||||
const options = {
|
||||
waitForInitialPage: false,
|
||||
// This is needed to prevent Puppeteer from adding an initial blank page.
|
||||
// See also https://github.com/puppeteer/puppeteer/blob/ad6b736039436fcc5c0a262e5b575aa041427be3/src/node/Launcher.ts#L200
|
||||
ignoreDefaultArgs: true,
|
||||
...defaultBrowserOptions,
|
||||
args: ['--no-startup-window'],
|
||||
};
|
||||
const browser = await puppeteer.launch(options);
|
||||
const pages = await browser.pages();
|
||||
expect(pages.length).toBe(0);
|
||||
await browser.close();
|
||||
}
|
||||
);
|
||||
it('should launch Chrome properly with --no-startup-window and waitForInitialPage=false', async () => {
|
||||
const {defaultBrowserOptions, puppeteer} = getTestState();
|
||||
const options = {
|
||||
waitForInitialPage: false,
|
||||
// This is needed to prevent Puppeteer from adding an initial blank page.
|
||||
// See also https://github.com/puppeteer/puppeteer/blob/ad6b736039436fcc5c0a262e5b575aa041427be3/src/node/Launcher.ts#L200
|
||||
ignoreDefaultArgs: true,
|
||||
...defaultBrowserOptions,
|
||||
args: ['--no-startup-window'],
|
||||
};
|
||||
const browser = await puppeteer.launch(options);
|
||||
const pages = await browser.pages();
|
||||
expect(pages.length).toBe(0);
|
||||
await browser.close();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Puppeteer.launch', function () {
|
||||
@ -775,7 +758,7 @@ describe('Launcher specs', function () {
|
||||
});
|
||||
|
||||
// @see https://github.com/puppeteer/puppeteer/issues/4197
|
||||
itFailsFirefox('should support targetFilter option', async () => {
|
||||
it('should support targetFilter option', async () => {
|
||||
const {server, puppeteer, defaultBrowserOptions} = getTestState();
|
||||
|
||||
const originalBrowser = await puppeteer.launch(defaultBrowserOptions);
|
||||
@ -809,68 +792,62 @@ describe('Launcher specs', function () {
|
||||
.sort()
|
||||
).toEqual(['about:blank', server.EMPTY_PAGE]);
|
||||
});
|
||||
itFailsFirefox(
|
||||
'should be able to reconnect to a disconnected browser',
|
||||
async () => {
|
||||
const {server, puppeteer, defaultBrowserOptions} = getTestState();
|
||||
it('should be able to reconnect to a disconnected browser', async () => {
|
||||
const {server, puppeteer, defaultBrowserOptions} = getTestState();
|
||||
|
||||
const originalBrowser = await puppeteer.launch(defaultBrowserOptions);
|
||||
const browserWSEndpoint = originalBrowser.wsEndpoint();
|
||||
const page = await originalBrowser.newPage();
|
||||
await page.goto(server.PREFIX + '/frames/nested-frames.html');
|
||||
originalBrowser.disconnect();
|
||||
const originalBrowser = await puppeteer.launch(defaultBrowserOptions);
|
||||
const browserWSEndpoint = originalBrowser.wsEndpoint();
|
||||
const page = await originalBrowser.newPage();
|
||||
await page.goto(server.PREFIX + '/frames/nested-frames.html');
|
||||
originalBrowser.disconnect();
|
||||
|
||||
const browser = await puppeteer.connect({browserWSEndpoint});
|
||||
const pages = await browser.pages();
|
||||
const restoredPage = pages.find(page => {
|
||||
return page.url() === server.PREFIX + '/frames/nested-frames.html';
|
||||
})!;
|
||||
expect(utils.dumpFrames(restoredPage.mainFrame())).toEqual([
|
||||
'http://localhost:<PORT>/frames/nested-frames.html',
|
||||
' http://localhost:<PORT>/frames/two-frames.html (2frames)',
|
||||
' http://localhost:<PORT>/frames/frame.html (uno)',
|
||||
' http://localhost:<PORT>/frames/frame.html (dos)',
|
||||
' http://localhost:<PORT>/frames/frame.html (aframe)',
|
||||
]);
|
||||
expect(
|
||||
await restoredPage.evaluate(() => {
|
||||
return 7 * 8;
|
||||
})
|
||||
).toBe(56);
|
||||
await browser.close();
|
||||
}
|
||||
);
|
||||
const browser = await puppeteer.connect({browserWSEndpoint});
|
||||
const pages = await browser.pages();
|
||||
const restoredPage = pages.find(page => {
|
||||
return page.url() === server.PREFIX + '/frames/nested-frames.html';
|
||||
})!;
|
||||
expect(utils.dumpFrames(restoredPage.mainFrame())).toEqual([
|
||||
'http://localhost:<PORT>/frames/nested-frames.html',
|
||||
' http://localhost:<PORT>/frames/two-frames.html (2frames)',
|
||||
' http://localhost:<PORT>/frames/frame.html (uno)',
|
||||
' http://localhost:<PORT>/frames/frame.html (dos)',
|
||||
' http://localhost:<PORT>/frames/frame.html (aframe)',
|
||||
]);
|
||||
expect(
|
||||
await restoredPage.evaluate(() => {
|
||||
return 7 * 8;
|
||||
})
|
||||
).toBe(56);
|
||||
await browser.close();
|
||||
});
|
||||
// @see https://github.com/puppeteer/puppeteer/issues/4197#issuecomment-481793410
|
||||
itFailsFirefox(
|
||||
'should be able to connect to the same page simultaneously',
|
||||
async () => {
|
||||
const {puppeteer, defaultBrowserOptions} = getTestState();
|
||||
it('should be able to connect to the same page simultaneously', async () => {
|
||||
const {puppeteer, defaultBrowserOptions} = getTestState();
|
||||
|
||||
const browserOne = await puppeteer.launch(defaultBrowserOptions);
|
||||
const browserTwo = await puppeteer.connect({
|
||||
browserWSEndpoint: browserOne.wsEndpoint(),
|
||||
});
|
||||
const [page1, page2] = await Promise.all([
|
||||
new Promise<Page>(x => {
|
||||
return browserOne.once('targetcreated', target => {
|
||||
return x(target.page());
|
||||
});
|
||||
}),
|
||||
browserTwo.newPage(),
|
||||
]);
|
||||
expect(
|
||||
await page1.evaluate(() => {
|
||||
return 7 * 8;
|
||||
})
|
||||
).toBe(56);
|
||||
expect(
|
||||
await page2.evaluate(() => {
|
||||
return 7 * 6;
|
||||
})
|
||||
).toBe(42);
|
||||
await browserOne.close();
|
||||
}
|
||||
);
|
||||
const browserOne = await puppeteer.launch(defaultBrowserOptions);
|
||||
const browserTwo = await puppeteer.connect({
|
||||
browserWSEndpoint: browserOne.wsEndpoint(),
|
||||
});
|
||||
const [page1, page2] = await Promise.all([
|
||||
new Promise<Page>(x => {
|
||||
return browserOne.once('targetcreated', target => {
|
||||
return x(target.page());
|
||||
});
|
||||
}),
|
||||
browserTwo.newPage(),
|
||||
]);
|
||||
expect(
|
||||
await page1.evaluate(() => {
|
||||
return 7 * 8;
|
||||
})
|
||||
).toBe(56);
|
||||
expect(
|
||||
await page2.evaluate(() => {
|
||||
return 7 * 6;
|
||||
})
|
||||
).toBe(42);
|
||||
await browserOne.close();
|
||||
});
|
||||
it('should be able to reconnect', async () => {
|
||||
const {puppeteer, server, defaultBrowserOptions} = getTestState();
|
||||
const browserOne = await puppeteer.launch(defaultBrowserOptions);
|
||||
@ -933,7 +910,7 @@ describe('Launcher specs', function () {
|
||||
|
||||
describe('when the product is chrome, platform is not darwin, and arch is arm64', () => {
|
||||
describe('and the executable exists', () => {
|
||||
itChromeOnly('returns /usr/bin/chromium-browser', async () => {
|
||||
it('returns /usr/bin/chromium-browser', async () => {
|
||||
const {puppeteer} = getTestState();
|
||||
const osPlatformStub = sinon.stub(os, 'platform').returns('linux');
|
||||
const osArchStub = sinon.stub(os, 'arch').returns('arm64');
|
||||
@ -972,33 +949,28 @@ describe('Launcher specs', function () {
|
||||
});
|
||||
});
|
||||
describe('and the executable does not exist', () => {
|
||||
itChromeOnly(
|
||||
'does not return /usr/bin/chromium-browser',
|
||||
async () => {
|
||||
const {puppeteer} = getTestState();
|
||||
const osPlatformStub = sinon
|
||||
.stub(os, 'platform')
|
||||
.returns('linux');
|
||||
const osArchStub = sinon.stub(os, 'arch').returns('arm64');
|
||||
const fsExistsStub = sinon.stub(fs, 'existsSync');
|
||||
fsExistsStub.withArgs('/usr/bin/chromium-browser').returns(false);
|
||||
it('does not return /usr/bin/chromium-browser', async () => {
|
||||
const {puppeteer} = getTestState();
|
||||
const osPlatformStub = sinon.stub(os, 'platform').returns('linux');
|
||||
const osArchStub = sinon.stub(os, 'arch').returns('arm64');
|
||||
const fsExistsStub = sinon.stub(fs, 'existsSync');
|
||||
fsExistsStub.withArgs('/usr/bin/chromium-browser').returns(false);
|
||||
|
||||
const executablePath = puppeteer.executablePath();
|
||||
const executablePath = puppeteer.executablePath();
|
||||
|
||||
expect(executablePath).not.toEqual('/usr/bin/chromium-browser');
|
||||
expect(executablePath).not.toEqual('/usr/bin/chromium-browser');
|
||||
|
||||
osPlatformStub.restore();
|
||||
osArchStub.restore();
|
||||
fsExistsStub.restore();
|
||||
}
|
||||
);
|
||||
osPlatformStub.restore();
|
||||
osArchStub.restore();
|
||||
fsExistsStub.restore();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Browser target events', function () {
|
||||
itFailsFirefox('should work', async () => {
|
||||
it('should work', async () => {
|
||||
const {server, puppeteer, defaultBrowserOptions} = getTestState();
|
||||
|
||||
const browser = await puppeteer.launch(defaultBrowserOptions);
|
||||
@ -1021,51 +993,48 @@ describe('Launcher specs', function () {
|
||||
});
|
||||
|
||||
describe('Browser.Events.disconnected', function () {
|
||||
itFailsFirefox(
|
||||
'should be emitted when: browser gets closed, disconnected or underlying websocket gets closed',
|
||||
async () => {
|
||||
const {puppeteer, defaultBrowserOptions} = getTestState();
|
||||
const originalBrowser = await puppeteer.launch(defaultBrowserOptions);
|
||||
const browserWSEndpoint = originalBrowser.wsEndpoint();
|
||||
const remoteBrowser1 = await puppeteer.connect({
|
||||
browserWSEndpoint,
|
||||
});
|
||||
const remoteBrowser2 = await puppeteer.connect({
|
||||
browserWSEndpoint,
|
||||
});
|
||||
it('should be emitted when: browser gets closed, disconnected or underlying websocket gets closed', async () => {
|
||||
const {puppeteer, defaultBrowserOptions} = getTestState();
|
||||
const originalBrowser = await puppeteer.launch(defaultBrowserOptions);
|
||||
const browserWSEndpoint = originalBrowser.wsEndpoint();
|
||||
const remoteBrowser1 = await puppeteer.connect({
|
||||
browserWSEndpoint,
|
||||
});
|
||||
const remoteBrowser2 = await puppeteer.connect({
|
||||
browserWSEndpoint,
|
||||
});
|
||||
|
||||
let disconnectedOriginal = 0;
|
||||
let disconnectedRemote1 = 0;
|
||||
let disconnectedRemote2 = 0;
|
||||
originalBrowser.on('disconnected', () => {
|
||||
return ++disconnectedOriginal;
|
||||
});
|
||||
remoteBrowser1.on('disconnected', () => {
|
||||
return ++disconnectedRemote1;
|
||||
});
|
||||
remoteBrowser2.on('disconnected', () => {
|
||||
return ++disconnectedRemote2;
|
||||
});
|
||||
let disconnectedOriginal = 0;
|
||||
let disconnectedRemote1 = 0;
|
||||
let disconnectedRemote2 = 0;
|
||||
originalBrowser.on('disconnected', () => {
|
||||
return ++disconnectedOriginal;
|
||||
});
|
||||
remoteBrowser1.on('disconnected', () => {
|
||||
return ++disconnectedRemote1;
|
||||
});
|
||||
remoteBrowser2.on('disconnected', () => {
|
||||
return ++disconnectedRemote2;
|
||||
});
|
||||
|
||||
await Promise.all([
|
||||
utils.waitEvent(remoteBrowser2, 'disconnected'),
|
||||
remoteBrowser2.disconnect(),
|
||||
]);
|
||||
await Promise.all([
|
||||
utils.waitEvent(remoteBrowser2, 'disconnected'),
|
||||
remoteBrowser2.disconnect(),
|
||||
]);
|
||||
|
||||
expect(disconnectedOriginal).toBe(0);
|
||||
expect(disconnectedRemote1).toBe(0);
|
||||
expect(disconnectedRemote2).toBe(1);
|
||||
expect(disconnectedOriginal).toBe(0);
|
||||
expect(disconnectedRemote1).toBe(0);
|
||||
expect(disconnectedRemote2).toBe(1);
|
||||
|
||||
await Promise.all([
|
||||
utils.waitEvent(remoteBrowser1, 'disconnected'),
|
||||
utils.waitEvent(originalBrowser, 'disconnected'),
|
||||
originalBrowser.close(),
|
||||
]);
|
||||
await Promise.all([
|
||||
utils.waitEvent(remoteBrowser1, 'disconnected'),
|
||||
utils.waitEvent(originalBrowser, 'disconnected'),
|
||||
originalBrowser.close(),
|
||||
]);
|
||||
|
||||
expect(disconnectedOriginal).toBe(1);
|
||||
expect(disconnectedRemote1).toBe(1);
|
||||
expect(disconnectedRemote2).toBe(1);
|
||||
}
|
||||
);
|
||||
expect(disconnectedOriginal).toBe(1);
|
||||
expect(disconnectedRemote1).toBe(1);
|
||||
expect(disconnectedRemote2).toBe(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -17,7 +17,6 @@
|
||||
import Protocol from 'devtools-protocol';
|
||||
import expect from 'expect';
|
||||
import * as fs from 'fs';
|
||||
import * as os from 'os';
|
||||
import * as path from 'path';
|
||||
import rimraf from 'rimraf';
|
||||
import sinon from 'sinon';
|
||||
@ -34,6 +33,8 @@ import {
|
||||
import puppeteer from '../../lib/cjs/puppeteer/puppeteer.js';
|
||||
import {TestServer} from '../../utils/testserver/lib/index.js';
|
||||
import {extendExpectWithToBeGolden} from './utils.js';
|
||||
import * as Mocha from 'mocha';
|
||||
import {getTestId} from '../../utils/mochaRunner/lib/utils.js';
|
||||
|
||||
const setupServer = async () => {
|
||||
const assetsPath = path.join(__dirname, '../assets');
|
||||
@ -63,14 +64,14 @@ export const getTestState = (): PuppeteerTestState => {
|
||||
};
|
||||
|
||||
const product =
|
||||
process.env['PRODUCT'] || process.env['PUPPETEER_PRODUCT'] || 'Chromium';
|
||||
process.env['PRODUCT'] || process.env['PUPPETEER_PRODUCT'] || 'chrome';
|
||||
|
||||
const alternativeInstall = process.env['PUPPETEER_ALT_INSTALL'] || false;
|
||||
|
||||
const headless = (process.env['HEADLESS'] || 'true').trim().toLowerCase();
|
||||
const isHeadless = headless === 'true' || headless === 'chrome';
|
||||
const isFirefox = product === 'firefox';
|
||||
const isChrome = product === 'Chromium';
|
||||
const isChrome = product === 'chrome';
|
||||
|
||||
let extraLaunchOptions = {};
|
||||
try {
|
||||
@ -125,7 +126,11 @@ declare module 'expect/build/types' {
|
||||
}
|
||||
|
||||
const setupGoldenAssertions = (): void => {
|
||||
const suffix = product.toLowerCase();
|
||||
let suffix = product.toLowerCase();
|
||||
if (suffix === 'chrome') {
|
||||
// TODO: to avoid moving golden folders.
|
||||
suffix = 'chromium';
|
||||
}
|
||||
const GOLDEN_DIR = path.join(__dirname, `../golden-${suffix}`);
|
||||
const OUTPUT_DIR = path.join(__dirname, `../output-${suffix}`);
|
||||
if (fs.existsSync(OUTPUT_DIR)) {
|
||||
@ -152,64 +157,9 @@ interface PuppeteerTestState {
|
||||
}
|
||||
const state: Partial<PuppeteerTestState> = {};
|
||||
|
||||
export const itFailsFirefox = (
|
||||
description: string,
|
||||
body: Mocha.Func
|
||||
): Mocha.Test => {
|
||||
if (isFirefox) {
|
||||
return xit(description, body);
|
||||
} else {
|
||||
return it(description, body);
|
||||
}
|
||||
};
|
||||
|
||||
export const itChromeOnly = (
|
||||
description: string,
|
||||
body: Mocha.Func
|
||||
): Mocha.Test => {
|
||||
if (isChrome) {
|
||||
return it(description, body);
|
||||
} else {
|
||||
return xit(description, body);
|
||||
}
|
||||
};
|
||||
|
||||
export const itHeadlessOnly = (
|
||||
description: string,
|
||||
body: Mocha.Func
|
||||
): Mocha.Test => {
|
||||
if (isChrome && isHeadless === true) {
|
||||
return it(description, body);
|
||||
} else {
|
||||
return xit(description, body);
|
||||
}
|
||||
};
|
||||
|
||||
export const itHeadfulOnly = (
|
||||
description: string,
|
||||
body: Mocha.Func
|
||||
): Mocha.Test => {
|
||||
if (isChrome && isHeadless === false) {
|
||||
return it(description, body);
|
||||
} else {
|
||||
return xit(description, body);
|
||||
}
|
||||
};
|
||||
|
||||
export const itFirefoxOnly = (
|
||||
description: string,
|
||||
body: Mocha.Func
|
||||
): Mocha.Test => {
|
||||
if (isFirefox) {
|
||||
return it(description, body);
|
||||
} else {
|
||||
return xit(description, body);
|
||||
}
|
||||
};
|
||||
|
||||
export const itOnlyRegularInstall = (
|
||||
description: string,
|
||||
body: Mocha.Func
|
||||
body: Mocha.AsyncFunc
|
||||
): Mocha.Test => {
|
||||
if (alternativeInstall || process.env['BINARY']) {
|
||||
return xit(description, body);
|
||||
@ -218,50 +168,10 @@ export const itOnlyRegularInstall = (
|
||||
}
|
||||
};
|
||||
|
||||
export const itFailsWindowsUntilDate = (
|
||||
date: Date,
|
||||
description: string,
|
||||
body: Mocha.Func
|
||||
): Mocha.Test => {
|
||||
if (os.platform() === 'win32' && Date.now() < date.getTime()) {
|
||||
// we are within the deferred time so skip the test
|
||||
return xit(description, body);
|
||||
}
|
||||
|
||||
return it(description, body);
|
||||
};
|
||||
|
||||
export const itFailsWindows = (
|
||||
description: string,
|
||||
body: Mocha.Func
|
||||
): Mocha.Test => {
|
||||
if (os.platform() === 'win32') {
|
||||
return xit(description, body);
|
||||
}
|
||||
return it(description, body);
|
||||
};
|
||||
|
||||
export const describeFailsFirefox = (
|
||||
description: string,
|
||||
body: (this: Mocha.Suite) => void
|
||||
): void | Mocha.Suite => {
|
||||
if (isFirefox) {
|
||||
return xdescribe(description, body);
|
||||
} else {
|
||||
return describe(description, body);
|
||||
}
|
||||
};
|
||||
|
||||
export const describeChromeOnly = (
|
||||
description: string,
|
||||
body: (this: Mocha.Suite) => void
|
||||
): Mocha.Suite | void => {
|
||||
if (isChrome) {
|
||||
return describe(description, body);
|
||||
}
|
||||
};
|
||||
|
||||
if (process.env['MOCHA_WORKER_ID'] === '0') {
|
||||
if (
|
||||
process.env['MOCHA_WORKER_ID'] === undefined ||
|
||||
process.env['MOCHA_WORKER_ID'] === '0'
|
||||
) {
|
||||
console.log(
|
||||
`Running unit tests with:
|
||||
-> product: ${product}
|
||||
@ -290,7 +200,7 @@ export const setupTestBrowserHooks = (): void => {
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
await state.browser!.close();
|
||||
await state.browser?.close();
|
||||
state.browser = undefined;
|
||||
});
|
||||
};
|
||||
@ -302,7 +212,7 @@ export const setupTestPageAndContextHooks = (): void => {
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await state.context!.close();
|
||||
await state.context?.close();
|
||||
state.context = undefined;
|
||||
state.page = undefined;
|
||||
});
|
||||
@ -387,3 +297,34 @@ export const shortWaitForArrayToHaveAtLeastNElements = async (
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
type SyncFn = (this: Mocha.Context) => void;
|
||||
|
||||
const skippedTests: string[] = process.env['PUPPETEER_SKIPPED_TEST_CONFIG']
|
||||
? JSON.parse(process.env['PUPPETEER_SKIPPED_TEST_CONFIG'])
|
||||
: [];
|
||||
|
||||
function skipTestIfNeeded(test: Mocha.Test): void {
|
||||
const testId = getTestId(test.file!, test.fullTitle());
|
||||
if (
|
||||
skippedTests.find(skippedTest => {
|
||||
return testId.startsWith(skippedTest);
|
||||
})
|
||||
) {
|
||||
try {
|
||||
test.skip();
|
||||
} catch {}
|
||||
}
|
||||
}
|
||||
|
||||
export function it(title: string, fn?: Mocha.AsyncFunc | SyncFn): Mocha.Test {
|
||||
const test = Mocha.it.call(null, title, fn as any);
|
||||
skipTestIfNeeded(test);
|
||||
return test;
|
||||
}
|
||||
|
||||
it.only = function (title: string, fn?: Mocha.AsyncFunc | SyncFn): Mocha.Test {
|
||||
const test = Mocha.it.only.call(null, title, fn as any);
|
||||
skipTestIfNeeded(test);
|
||||
return test;
|
||||
};
|
||||
|
@ -19,9 +19,9 @@ import {
|
||||
getTestState,
|
||||
setupTestBrowserHooks,
|
||||
setupTestPageAndContextHooks,
|
||||
itFailsFirefox,
|
||||
} from './mocha-utils.js';
|
||||
import {KeyInput} from '../../lib/cjs/puppeteer/common/USKeyboardLayout.js';
|
||||
import {it} from './mocha-utils.js';
|
||||
|
||||
interface Dimensions {
|
||||
x: number;
|
||||
@ -115,7 +115,7 @@ describe('Mouse', function () {
|
||||
})
|
||||
).toBe(text);
|
||||
});
|
||||
itFailsFirefox('should trigger hover state', async () => {
|
||||
it('should trigger hover state', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
await page.goto(server.PREFIX + '/input/scrollable.html');
|
||||
@ -138,24 +138,21 @@ describe('Mouse', function () {
|
||||
})
|
||||
).toBe('button-91');
|
||||
});
|
||||
itFailsFirefox(
|
||||
'should trigger hover state with removed window.Node',
|
||||
async () => {
|
||||
const {page, server} = getTestState();
|
||||
it('should trigger hover state with removed window.Node', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
await page.goto(server.PREFIX + '/input/scrollable.html');
|
||||
await page.goto(server.PREFIX + '/input/scrollable.html');
|
||||
await page.evaluate(() => {
|
||||
// @ts-expect-error Expected.
|
||||
return delete window.Node;
|
||||
});
|
||||
await page.hover('#button-6');
|
||||
expect(
|
||||
await page.evaluate(() => {
|
||||
// @ts-expect-error Expected.
|
||||
return delete window.Node;
|
||||
});
|
||||
await page.hover('#button-6');
|
||||
expect(
|
||||
await page.evaluate(() => {
|
||||
return document.querySelector('button:hover')!.id;
|
||||
})
|
||||
).toBe('button-6');
|
||||
}
|
||||
);
|
||||
return document.querySelector('button:hover')!.id;
|
||||
})
|
||||
).toBe('button-6');
|
||||
});
|
||||
it('should set modifier keys on click', async () => {
|
||||
const {page, server, isFirefox} = getTestState();
|
||||
|
||||
@ -202,7 +199,7 @@ describe('Mouse', function () {
|
||||
}
|
||||
}
|
||||
});
|
||||
itFailsFirefox('should send mouse wheel events', async () => {
|
||||
it('should send mouse wheel events', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
await page.goto(server.PREFIX + '/input/wheel.html');
|
||||
@ -225,7 +222,7 @@ describe('Mouse', function () {
|
||||
height: 230,
|
||||
});
|
||||
});
|
||||
itFailsFirefox('should tween mouse movement', async () => {
|
||||
it('should tween mouse movement', async () => {
|
||||
const {page} = getTestState();
|
||||
|
||||
await page.mouse.move(100, 100);
|
||||
|
@ -20,12 +20,11 @@ import {
|
||||
getTestState,
|
||||
setupTestBrowserHooks,
|
||||
setupTestPageAndContextHooks,
|
||||
itFailsFirefox,
|
||||
describeFailsFirefox,
|
||||
} from './mocha-utils.js';
|
||||
import os from 'os';
|
||||
import {ServerResponse} from 'http';
|
||||
import {HTTPRequest} from '../../lib/cjs/puppeteer/common/HTTPRequest.js';
|
||||
import {it} from './mocha-utils.js';
|
||||
|
||||
describe('navigation', function () {
|
||||
setupTestBrowserHooks();
|
||||
@ -67,7 +66,7 @@ describe('navigation', function () {
|
||||
const response = (await page.goto(server.PREFIX + '/historyapi.html'))!;
|
||||
expect(response.status()).toBe(200);
|
||||
});
|
||||
itFailsFirefox('should work with subframes return 204', async () => {
|
||||
it('should work with subframes return 204', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
server.setRoute('/frames/frame.html', (_req, res) => {
|
||||
@ -82,7 +81,7 @@ describe('navigation', function () {
|
||||
});
|
||||
expect(error).toBeUndefined();
|
||||
});
|
||||
itFailsFirefox('should fail when server returns 204', async () => {
|
||||
it('should fail when server returns 204', async () => {
|
||||
const {page, server, isChrome} = getTestState();
|
||||
|
||||
server.setRoute('/empty.html', (_req, res) => {
|
||||
@ -124,29 +123,23 @@ describe('navigation', function () {
|
||||
const response = await page.goto(server.PREFIX + '/grid.html');
|
||||
expect(response!.status()).toBe(200);
|
||||
});
|
||||
itFailsFirefox(
|
||||
'should navigate to empty page with networkidle0',
|
||||
async () => {
|
||||
const {page, server} = getTestState();
|
||||
it('should navigate to empty page with networkidle0', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
const response = await page.goto(server.EMPTY_PAGE, {
|
||||
waitUntil: 'networkidle0',
|
||||
});
|
||||
expect(response!.status()).toBe(200);
|
||||
}
|
||||
);
|
||||
itFailsFirefox(
|
||||
'should navigate to empty page with networkidle2',
|
||||
async () => {
|
||||
const {page, server} = getTestState();
|
||||
const response = await page.goto(server.EMPTY_PAGE, {
|
||||
waitUntil: 'networkidle0',
|
||||
});
|
||||
expect(response!.status()).toBe(200);
|
||||
});
|
||||
it('should navigate to empty page with networkidle2', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
const response = await page.goto(server.EMPTY_PAGE, {
|
||||
waitUntil: 'networkidle2',
|
||||
});
|
||||
expect(response!.status()).toBe(200);
|
||||
}
|
||||
);
|
||||
itFailsFirefox('should fail when navigating to bad url', async () => {
|
||||
const response = await page.goto(server.EMPTY_PAGE, {
|
||||
waitUntil: 'networkidle2',
|
||||
});
|
||||
expect(response!.status()).toBe(200);
|
||||
});
|
||||
it('should fail when navigating to bad url', async () => {
|
||||
const {page, isChrome} = getTestState();
|
||||
|
||||
let error!: Error;
|
||||
@ -175,7 +168,7 @@ describe('navigation', function () {
|
||||
: 'net::ERR_CERT_AUTHORITY_INVALID';
|
||||
}
|
||||
|
||||
itFailsFirefox('should fail when navigating to bad SSL', async () => {
|
||||
it('should fail when navigating to bad SSL', async () => {
|
||||
const {page, httpsServer, isChrome} = getTestState();
|
||||
|
||||
// Make sure that network events do not emit 'undefined'.
|
||||
@ -311,7 +304,7 @@ describe('navigation', function () {
|
||||
const response = (await page.goto(server.EMPTY_PAGE))!;
|
||||
expect(response.ok()).toBe(true);
|
||||
});
|
||||
itFailsFirefox('should work when navigating to data url', async () => {
|
||||
it('should work when navigating to data url', async () => {
|
||||
const {page} = getTestState();
|
||||
|
||||
const response = (await page.goto('data:text/html,hello'))!;
|
||||
@ -334,85 +327,79 @@ describe('navigation', function () {
|
||||
expect(response.ok()).toBe(true);
|
||||
expect(response.url()).toBe(server.EMPTY_PAGE);
|
||||
});
|
||||
itFailsFirefox(
|
||||
'should wait for network idle to succeed navigation',
|
||||
async () => {
|
||||
const {page, server} = getTestState();
|
||||
it('should wait for network idle to succeed navigation', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
let responses: ServerResponse[] = [];
|
||||
// Hold on to a bunch of requests without answering.
|
||||
server.setRoute('/fetch-request-a.js', (_req, res) => {
|
||||
return responses.push(res);
|
||||
});
|
||||
server.setRoute('/fetch-request-b.js', (_req, res) => {
|
||||
return responses.push(res);
|
||||
});
|
||||
server.setRoute('/fetch-request-c.js', (_req, res) => {
|
||||
return responses.push(res);
|
||||
});
|
||||
server.setRoute('/fetch-request-d.js', (_req, res) => {
|
||||
return responses.push(res);
|
||||
});
|
||||
const initialFetchResourcesRequested = Promise.all([
|
||||
server.waitForRequest('/fetch-request-a.js'),
|
||||
server.waitForRequest('/fetch-request-b.js'),
|
||||
server.waitForRequest('/fetch-request-c.js'),
|
||||
]);
|
||||
const secondFetchResourceRequested = server.waitForRequest(
|
||||
'/fetch-request-d.js'
|
||||
);
|
||||
let responses: ServerResponse[] = [];
|
||||
// Hold on to a bunch of requests without answering.
|
||||
server.setRoute('/fetch-request-a.js', (_req, res) => {
|
||||
return responses.push(res);
|
||||
});
|
||||
server.setRoute('/fetch-request-b.js', (_req, res) => {
|
||||
return responses.push(res);
|
||||
});
|
||||
server.setRoute('/fetch-request-c.js', (_req, res) => {
|
||||
return responses.push(res);
|
||||
});
|
||||
server.setRoute('/fetch-request-d.js', (_req, res) => {
|
||||
return responses.push(res);
|
||||
});
|
||||
const initialFetchResourcesRequested = Promise.all([
|
||||
server.waitForRequest('/fetch-request-a.js'),
|
||||
server.waitForRequest('/fetch-request-b.js'),
|
||||
server.waitForRequest('/fetch-request-c.js'),
|
||||
]);
|
||||
const secondFetchResourceRequested = server.waitForRequest(
|
||||
'/fetch-request-d.js'
|
||||
);
|
||||
|
||||
// Navigate to a page which loads immediately and then does a bunch of
|
||||
// requests via javascript's fetch method.
|
||||
const navigationPromise = page.goto(
|
||||
server.PREFIX + '/networkidle.html',
|
||||
{
|
||||
waitUntil: 'networkidle0',
|
||||
}
|
||||
);
|
||||
// Track when the navigation gets completed.
|
||||
let navigationFinished = false;
|
||||
navigationPromise.then(() => {
|
||||
return (navigationFinished = true);
|
||||
});
|
||||
// Navigate to a page which loads immediately and then does a bunch of
|
||||
// requests via javascript's fetch method.
|
||||
const navigationPromise = page.goto(server.PREFIX + '/networkidle.html', {
|
||||
waitUntil: 'networkidle0',
|
||||
});
|
||||
// Track when the navigation gets completed.
|
||||
let navigationFinished = false;
|
||||
navigationPromise.then(() => {
|
||||
return (navigationFinished = true);
|
||||
});
|
||||
|
||||
// Wait for the page's 'load' event.
|
||||
await new Promise(fulfill => {
|
||||
return page.once('load', fulfill);
|
||||
});
|
||||
expect(navigationFinished).toBe(false);
|
||||
// Wait for the page's 'load' event.
|
||||
await new Promise(fulfill => {
|
||||
return page.once('load', fulfill);
|
||||
});
|
||||
expect(navigationFinished).toBe(false);
|
||||
|
||||
// Wait for the initial three resources to be requested.
|
||||
await initialFetchResourcesRequested;
|
||||
// Wait for the initial three resources to be requested.
|
||||
await initialFetchResourcesRequested;
|
||||
|
||||
// Expect navigation still to be not finished.
|
||||
expect(navigationFinished).toBe(false);
|
||||
// Expect navigation still to be not finished.
|
||||
expect(navigationFinished).toBe(false);
|
||||
|
||||
// Respond to initial requests.
|
||||
for (const response of responses) {
|
||||
response.statusCode = 404;
|
||||
response.end(`File not found`);
|
||||
}
|
||||
|
||||
// Reset responses array
|
||||
responses = [];
|
||||
|
||||
// Wait for the second round to be requested.
|
||||
await secondFetchResourceRequested;
|
||||
// Expect navigation still to be not finished.
|
||||
expect(navigationFinished).toBe(false);
|
||||
|
||||
// Respond to requests.
|
||||
for (const response of responses) {
|
||||
response.statusCode = 404;
|
||||
response.end(`File not found`);
|
||||
}
|
||||
|
||||
const response = (await navigationPromise)!;
|
||||
// Expect navigation to succeed.
|
||||
expect(response.ok()).toBe(true);
|
||||
// Respond to initial requests.
|
||||
for (const response of responses) {
|
||||
response.statusCode = 404;
|
||||
response.end(`File not found`);
|
||||
}
|
||||
);
|
||||
|
||||
// Reset responses array
|
||||
responses = [];
|
||||
|
||||
// Wait for the second round to be requested.
|
||||
await secondFetchResourceRequested;
|
||||
// Expect navigation still to be not finished.
|
||||
expect(navigationFinished).toBe(false);
|
||||
|
||||
// Respond to requests.
|
||||
for (const response of responses) {
|
||||
response.statusCode = 404;
|
||||
response.end(`File not found`);
|
||||
}
|
||||
|
||||
const response = (await navigationPromise)!;
|
||||
// Expect navigation to succeed.
|
||||
expect(response.ok()).toBe(true);
|
||||
});
|
||||
it('should not leak listeners during navigation', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
@ -461,38 +448,32 @@ describe('navigation', function () {
|
||||
process.removeListener('warning', warningHandler);
|
||||
expect(warning).toBe(null);
|
||||
});
|
||||
itFailsFirefox(
|
||||
'should navigate to dataURL and fire dataURL requests',
|
||||
async () => {
|
||||
const {page} = getTestState();
|
||||
it('should navigate to dataURL and fire dataURL requests', async () => {
|
||||
const {page} = getTestState();
|
||||
|
||||
const requests: HTTPRequest[] = [];
|
||||
page.on('request', request => {
|
||||
return !utils.isFavicon(request) && requests.push(request);
|
||||
});
|
||||
const dataURL = 'data:text/html,<div>yo</div>';
|
||||
const response = (await page.goto(dataURL))!;
|
||||
expect(response.status()).toBe(200);
|
||||
expect(requests.length).toBe(1);
|
||||
expect(requests[0]!.url()).toBe(dataURL);
|
||||
}
|
||||
);
|
||||
itFailsFirefox(
|
||||
'should navigate to URL with hash and fire requests without hash',
|
||||
async () => {
|
||||
const {page, server} = getTestState();
|
||||
const requests: HTTPRequest[] = [];
|
||||
page.on('request', request => {
|
||||
return !utils.isFavicon(request) && requests.push(request);
|
||||
});
|
||||
const dataURL = 'data:text/html,<div>yo</div>';
|
||||
const response = (await page.goto(dataURL))!;
|
||||
expect(response.status()).toBe(200);
|
||||
expect(requests.length).toBe(1);
|
||||
expect(requests[0]!.url()).toBe(dataURL);
|
||||
});
|
||||
it('should navigate to URL with hash and fire requests without hash', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
const requests: HTTPRequest[] = [];
|
||||
page.on('request', request => {
|
||||
return !utils.isFavicon(request) && requests.push(request);
|
||||
});
|
||||
const response = (await page.goto(server.EMPTY_PAGE + '#hash'))!;
|
||||
expect(response.status()).toBe(200);
|
||||
expect(response.url()).toBe(server.EMPTY_PAGE);
|
||||
expect(requests.length).toBe(1);
|
||||
expect(requests[0]!.url()).toBe(server.EMPTY_PAGE);
|
||||
}
|
||||
);
|
||||
const requests: HTTPRequest[] = [];
|
||||
page.on('request', request => {
|
||||
return !utils.isFavicon(request) && requests.push(request);
|
||||
});
|
||||
const response = (await page.goto(server.EMPTY_PAGE + '#hash'))!;
|
||||
expect(response.status()).toBe(200);
|
||||
expect(response.url()).toBe(server.EMPTY_PAGE);
|
||||
expect(requests.length).toBe(1);
|
||||
expect(requests[0]!.url()).toBe(server.EMPTY_PAGE);
|
||||
});
|
||||
it('should work with self requesting page', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
@ -512,7 +493,7 @@ describe('navigation', function () {
|
||||
}
|
||||
expect(error.message).toContain(url);
|
||||
});
|
||||
itFailsFirefox('should send referer', async () => {
|
||||
it('should send referer', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
const [request1, request2] = await Promise.all([
|
||||
@ -582,7 +563,7 @@ describe('navigation', function () {
|
||||
expect(response).toBe(null);
|
||||
expect(page.url()).toBe(server.EMPTY_PAGE + '#foobar');
|
||||
});
|
||||
itFailsFirefox('should work with history.pushState()', async () => {
|
||||
it('should work with history.pushState()', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
@ -599,7 +580,7 @@ describe('navigation', function () {
|
||||
expect(response).toBe(null);
|
||||
expect(page.url()).toBe(server.PREFIX + '/wow.html');
|
||||
});
|
||||
itFailsFirefox('should work with history.replaceState()', async () => {
|
||||
it('should work with history.replaceState()', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
@ -616,13 +597,11 @@ describe('navigation', function () {
|
||||
expect(response).toBe(null);
|
||||
expect(page.url()).toBe(server.PREFIX + '/replaced.html');
|
||||
});
|
||||
itFailsFirefox(
|
||||
'should work with DOM history.back()/history.forward()',
|
||||
async () => {
|
||||
const {page, server} = getTestState();
|
||||
it('should work with DOM history.back()/history.forward()', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
await page.setContent(`
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
await page.setContent(`
|
||||
<a id=back onclick='javascript:goBack()'>back</a>
|
||||
<a id=forward onclick='javascript:goForward()'>forward</a>
|
||||
<script>
|
||||
@ -632,46 +611,42 @@ describe('navigation', function () {
|
||||
history.pushState({}, '', '/second.html');
|
||||
</script>
|
||||
`);
|
||||
expect(page.url()).toBe(server.PREFIX + '/second.html');
|
||||
const [backResponse] = await Promise.all([
|
||||
page.waitForNavigation(),
|
||||
page.click('a#back'),
|
||||
]);
|
||||
expect(backResponse).toBe(null);
|
||||
expect(page.url()).toBe(server.PREFIX + '/first.html');
|
||||
const [forwardResponse] = await Promise.all([
|
||||
page.waitForNavigation(),
|
||||
page.click('a#forward'),
|
||||
]);
|
||||
expect(forwardResponse).toBe(null);
|
||||
expect(page.url()).toBe(server.PREFIX + '/second.html');
|
||||
}
|
||||
);
|
||||
itFailsFirefox(
|
||||
'should work when subframe issues window.stop()',
|
||||
async () => {
|
||||
const {page, server} = getTestState();
|
||||
expect(page.url()).toBe(server.PREFIX + '/second.html');
|
||||
const [backResponse] = await Promise.all([
|
||||
page.waitForNavigation(),
|
||||
page.click('a#back'),
|
||||
]);
|
||||
expect(backResponse).toBe(null);
|
||||
expect(page.url()).toBe(server.PREFIX + '/first.html');
|
||||
const [forwardResponse] = await Promise.all([
|
||||
page.waitForNavigation(),
|
||||
page.click('a#forward'),
|
||||
]);
|
||||
expect(forwardResponse).toBe(null);
|
||||
expect(page.url()).toBe(server.PREFIX + '/second.html');
|
||||
});
|
||||
it('should work when subframe issues window.stop()', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
server.setRoute('/frames/style.css', () => {});
|
||||
const navigationPromise = page.goto(
|
||||
server.PREFIX + '/frames/one-frame.html'
|
||||
);
|
||||
const frame = await utils.waitEvent(page, 'frameattached');
|
||||
await new Promise<void>(fulfill => {
|
||||
page.on('framenavigated', f => {
|
||||
if (f === frame) {
|
||||
fulfill();
|
||||
}
|
||||
});
|
||||
server.setRoute('/frames/style.css', () => {});
|
||||
const navigationPromise = page.goto(
|
||||
server.PREFIX + '/frames/one-frame.html'
|
||||
);
|
||||
const frame = await utils.waitEvent(page, 'frameattached');
|
||||
await new Promise<void>(fulfill => {
|
||||
page.on('framenavigated', f => {
|
||||
if (f === frame) {
|
||||
fulfill();
|
||||
}
|
||||
});
|
||||
await Promise.all([
|
||||
frame.evaluate(() => {
|
||||
return window.stop();
|
||||
}),
|
||||
navigationPromise,
|
||||
]);
|
||||
}
|
||||
);
|
||||
});
|
||||
await Promise.all([
|
||||
frame.evaluate(() => {
|
||||
return window.stop();
|
||||
}),
|
||||
navigationPromise,
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Page.goBack', function () {
|
||||
@ -692,7 +667,7 @@ describe('navigation', function () {
|
||||
response = (await page.goForward())!;
|
||||
expect(response).toBe(null);
|
||||
});
|
||||
itFailsFirefox('should work with HistoryAPI', async () => {
|
||||
it('should work with HistoryAPI', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
@ -711,7 +686,7 @@ describe('navigation', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describeFailsFirefox('Frame.goto', function () {
|
||||
describe('Frame.goto', function () {
|
||||
it('should navigate subframes', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
@ -776,7 +751,7 @@ describe('navigation', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describeFailsFirefox('Frame.waitForNavigation', function () {
|
||||
describe('Frame.waitForNavigation', function () {
|
||||
it('should work', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
|
@ -22,14 +22,11 @@ import {
|
||||
getTestState,
|
||||
setupTestBrowserHooks,
|
||||
setupTestPageAndContextHooks,
|
||||
itFailsFirefox,
|
||||
describeFailsFirefox,
|
||||
itChromeOnly,
|
||||
itFirefoxOnly,
|
||||
} from './mocha-utils.js';
|
||||
import {HTTPRequest} from '../../lib/cjs/puppeteer/common/HTTPRequest.js';
|
||||
import {HTTPResponse} from '../../lib/cjs/puppeteer/common/HTTPResponse.js';
|
||||
import {ServerResponse} from 'http';
|
||||
import {it} from './mocha-utils.js';
|
||||
|
||||
describe('network', function () {
|
||||
setupTestBrowserHooks();
|
||||
@ -83,7 +80,7 @@ describe('network', function () {
|
||||
expect(requests.length).toBe(1);
|
||||
expect(requests[0]!.frame()).toBe(page.mainFrame());
|
||||
});
|
||||
itFailsFirefox('should work for subframe navigation request', async () => {
|
||||
it('should work for subframe navigation request', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
(await page.goto(server.EMPTY_PAGE))!;
|
||||
@ -115,13 +112,13 @@ describe('network', function () {
|
||||
});
|
||||
|
||||
describe('Request.headers', function () {
|
||||
itChromeOnly('should define Chrome as user agent header', async () => {
|
||||
it('should define Chrome as user agent header', async () => {
|
||||
const {page, server} = getTestState();
|
||||
const response = (await page.goto(server.EMPTY_PAGE))!;
|
||||
expect(response.request().headers()['user-agent']).toContain('Chrome');
|
||||
});
|
||||
|
||||
itFirefoxOnly('should define Firefox as user agent header', async () => {
|
||||
it('should define Firefox as user agent header', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
const response = (await page.goto(server.EMPTY_PAGE))!;
|
||||
@ -142,7 +139,7 @@ describe('network', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describeFailsFirefox('Request.initiator', () => {
|
||||
describe('Request.initiator', () => {
|
||||
it('should return the initiator', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
@ -187,7 +184,7 @@ describe('network', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describeFailsFirefox('Response.fromCache', function () {
|
||||
describe('Response.fromCache', function () {
|
||||
it('should return |false| for non-cached content', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
@ -218,7 +215,7 @@ describe('network', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describeFailsFirefox('Response.fromServiceWorker', function () {
|
||||
describe('Response.fromServiceWorker', function () {
|
||||
it('should return |false| for non-service-worker content', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
@ -253,7 +250,7 @@ describe('network', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describeFailsFirefox('Request.postData', function () {
|
||||
describe('Request.postData', function () {
|
||||
it('should work', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
@ -284,7 +281,7 @@ describe('network', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describeFailsFirefox('Response.text', function () {
|
||||
describe('Response.text', function () {
|
||||
it('should work', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
@ -367,7 +364,7 @@ describe('network', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describeFailsFirefox('Response.json', function () {
|
||||
describe('Response.json', function () {
|
||||
it('should work', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
@ -376,7 +373,7 @@ describe('network', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describeFailsFirefox('Response.buffer', function () {
|
||||
describe('Response.buffer', function () {
|
||||
it('should work', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
@ -461,7 +458,7 @@ describe('network', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describeFailsFirefox('Response.timing', function () {
|
||||
describe('Response.timing', function () {
|
||||
it('returns timing information', async () => {
|
||||
const {page, server} = getTestState();
|
||||
const responses: HTTPResponse[] = [];
|
||||
@ -474,7 +471,7 @@ describe('network', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describeFailsFirefox('Network Events', function () {
|
||||
describe('Network Events', function () {
|
||||
it('Page.Events.Request', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
@ -624,7 +621,7 @@ describe('network', function () {
|
||||
});
|
||||
|
||||
describe('Request.isNavigationRequest', () => {
|
||||
itFailsFirefox('should work', async () => {
|
||||
it('should work', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
const requests = new Map();
|
||||
@ -639,7 +636,7 @@ describe('network', function () {
|
||||
expect(requests.get('script.js').isNavigationRequest()).toBe(false);
|
||||
expect(requests.get('style.css').isNavigationRequest()).toBe(false);
|
||||
});
|
||||
itFailsFirefox('should work with request interception', async () => {
|
||||
it('should work with request interception', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
const requests = new Map();
|
||||
@ -656,7 +653,7 @@ describe('network', function () {
|
||||
expect(requests.get('script.js').isNavigationRequest()).toBe(false);
|
||||
expect(requests.get('style.css').isNavigationRequest()).toBe(false);
|
||||
});
|
||||
itFailsFirefox('should work when navigating to image', async () => {
|
||||
it('should work when navigating to image', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
const requests: HTTPRequest[] = [];
|
||||
@ -668,7 +665,7 @@ describe('network', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describeFailsFirefox('Page.setExtraHTTPHeaders', function () {
|
||||
describe('Page.setExtraHTTPHeaders', function () {
|
||||
it('should work', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
@ -697,7 +694,7 @@ describe('network', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describeFailsFirefox('Page.authenticate', function () {
|
||||
describe('Page.authenticate', function () {
|
||||
it('should work', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
@ -794,7 +791,7 @@ describe('network', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describeFailsFirefox('raw network headers', async () => {
|
||||
describe('raw network headers', async () => {
|
||||
it('Same-origin set-cookie navigation', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
|
@ -16,18 +16,15 @@
|
||||
|
||||
import utils from './utils.js';
|
||||
import expect from 'expect';
|
||||
import {
|
||||
getTestState,
|
||||
describeChromeOnly,
|
||||
itFailsFirefox,
|
||||
} from './mocha-utils.js';
|
||||
import {getTestState} from './mocha-utils.js';
|
||||
import {
|
||||
Browser,
|
||||
BrowserContext,
|
||||
} from '../../lib/cjs/puppeteer/common/Browser.js';
|
||||
import {Page} from '../../lib/cjs/puppeteer/common/Page.js';
|
||||
import {it} from './mocha-utils.js';
|
||||
|
||||
describeChromeOnly('OOPIF', function () {
|
||||
describe('OOPIF', function () {
|
||||
/* We use a special browser for this test as we need the --site-per-process flag */
|
||||
let browser: Browser;
|
||||
let context: BrowserContext;
|
||||
@ -207,6 +204,7 @@ describeChromeOnly('OOPIF', function () {
|
||||
await utils.navigateFrame(page, 'frame1', server.EMPTY_PAGE);
|
||||
expect(frame.url()).toBe(server.EMPTY_PAGE);
|
||||
});
|
||||
|
||||
it('should support evaluating in oop iframes', async () => {
|
||||
const {server} = getTestState();
|
||||
|
||||
@ -420,7 +418,7 @@ describeChromeOnly('OOPIF', function () {
|
||||
browser1.disconnect();
|
||||
});
|
||||
|
||||
itFailsFirefox('should support lazy OOP frames', async () => {
|
||||
it('should support lazy OOP frames', async () => {
|
||||
const {server} = getTestState();
|
||||
|
||||
await page.goto(server.PREFIX + '/lazy-oopif-frame.html');
|
||||
|
@ -22,13 +22,12 @@ import {CDPSession} from '../../lib/cjs/puppeteer/common/Connection.js';
|
||||
import {ConsoleMessage} from '../../lib/cjs/puppeteer/common/ConsoleMessage.js';
|
||||
import {Metrics, Page} from '../../lib/cjs/puppeteer/common/Page.js';
|
||||
import {
|
||||
describeFailsFirefox,
|
||||
getTestState,
|
||||
itFailsFirefox,
|
||||
setupTestBrowserHooks,
|
||||
setupTestPageAndContextHooks,
|
||||
} from './mocha-utils.js';
|
||||
import utils, {attachFrame, waitEvent} from './utils.js';
|
||||
import {it} from './mocha-utils.js';
|
||||
|
||||
describe('Page', function () {
|
||||
setupTestBrowserHooks();
|
||||
@ -59,7 +58,7 @@ describe('Page', function () {
|
||||
await newPage.close();
|
||||
expect(await browser.pages()).not.toContain(newPage);
|
||||
});
|
||||
itFailsFirefox('should run beforeunload if asked for', async () => {
|
||||
it('should run beforeunload if asked for', async () => {
|
||||
const {context, server, isChrome} = getTestState();
|
||||
|
||||
const newPage = await context.newPage();
|
||||
@ -79,7 +78,7 @@ describe('Page', function () {
|
||||
await dialog.accept();
|
||||
await pageClosingPromise;
|
||||
});
|
||||
itFailsFirefox('should *not* run beforeunload by default', async () => {
|
||||
it('should *not* run beforeunload by default', async () => {
|
||||
const {context, server} = getTestState();
|
||||
|
||||
const newPage = await context.newPage();
|
||||
@ -97,7 +96,7 @@ describe('Page', function () {
|
||||
await newPage.close();
|
||||
expect(newPage.isClosed()).toBe(true);
|
||||
});
|
||||
itFailsFirefox('should terminate network waiters', async () => {
|
||||
it('should terminate network waiters', async () => {
|
||||
const {context, server} = getTestState();
|
||||
|
||||
const newPage = await context.newPage();
|
||||
@ -182,7 +181,7 @@ describe('Page', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describeFailsFirefox('Page.Events.error', function () {
|
||||
describe('Page.Events.error', function () {
|
||||
it('should throw when page crashes', async () => {
|
||||
const {page} = getTestState();
|
||||
|
||||
@ -196,7 +195,7 @@ describe('Page', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describeFailsFirefox('Page.Events.Popup', function () {
|
||||
describe('Page.Events.Popup', function () {
|
||||
it('should work', async () => {
|
||||
const {page} = getTestState();
|
||||
|
||||
@ -354,7 +353,7 @@ describe('Page', function () {
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
expect(await getPermission(page, 'geolocation')).toBe('prompt');
|
||||
});
|
||||
itFailsFirefox('should deny permission when not listed', async () => {
|
||||
it('should deny permission when not listed', async () => {
|
||||
const {page, server, context} = getTestState();
|
||||
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
@ -374,14 +373,14 @@ describe('Page', function () {
|
||||
});
|
||||
expect(error.message).toBe('Unknown permission: foo');
|
||||
});
|
||||
itFailsFirefox('should grant permission when listed', async () => {
|
||||
it('should grant permission when listed', async () => {
|
||||
const {page, server, context} = getTestState();
|
||||
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
await context.overridePermissions(server.EMPTY_PAGE, ['geolocation']);
|
||||
expect(await getPermission(page, 'geolocation')).toBe('granted');
|
||||
});
|
||||
itFailsFirefox('should reset permissions', async () => {
|
||||
it('should reset permissions', async () => {
|
||||
const {page, server, context} = getTestState();
|
||||
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
@ -390,7 +389,7 @@ describe('Page', function () {
|
||||
await context.clearPermissionOverrides();
|
||||
expect(await getPermission(page, 'geolocation')).toBe('prompt');
|
||||
});
|
||||
itFailsFirefox('should trigger permission onchange', async () => {
|
||||
it('should trigger permission onchange', async () => {
|
||||
const {page, server, context, isHeadless} = getTestState();
|
||||
|
||||
// TODO: re-enable this test in headful once crbug.com/1324480 rolls out.
|
||||
@ -434,33 +433,30 @@ describe('Page', function () {
|
||||
})
|
||||
).toEqual(['prompt', 'denied', 'granted', 'prompt']);
|
||||
});
|
||||
itFailsFirefox(
|
||||
'should isolate permissions between browser contexts',
|
||||
async () => {
|
||||
const {page, server, context, browser} = getTestState();
|
||||
it('should isolate permissions between browser contexts', async () => {
|
||||
const {page, server, context, browser} = getTestState();
|
||||
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
const otherContext = await browser.createIncognitoBrowserContext();
|
||||
const otherPage = await otherContext.newPage();
|
||||
await otherPage.goto(server.EMPTY_PAGE);
|
||||
expect(await getPermission(page, 'geolocation')).toBe('prompt');
|
||||
expect(await getPermission(otherPage, 'geolocation')).toBe('prompt');
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
const otherContext = await browser.createIncognitoBrowserContext();
|
||||
const otherPage = await otherContext.newPage();
|
||||
await otherPage.goto(server.EMPTY_PAGE);
|
||||
expect(await getPermission(page, 'geolocation')).toBe('prompt');
|
||||
expect(await getPermission(otherPage, 'geolocation')).toBe('prompt');
|
||||
|
||||
await context.overridePermissions(server.EMPTY_PAGE, []);
|
||||
await otherContext.overridePermissions(server.EMPTY_PAGE, [
|
||||
'geolocation',
|
||||
]);
|
||||
expect(await getPermission(page, 'geolocation')).toBe('denied');
|
||||
expect(await getPermission(otherPage, 'geolocation')).toBe('granted');
|
||||
await context.overridePermissions(server.EMPTY_PAGE, []);
|
||||
await otherContext.overridePermissions(server.EMPTY_PAGE, [
|
||||
'geolocation',
|
||||
]);
|
||||
expect(await getPermission(page, 'geolocation')).toBe('denied');
|
||||
expect(await getPermission(otherPage, 'geolocation')).toBe('granted');
|
||||
|
||||
await context.clearPermissionOverrides();
|
||||
expect(await getPermission(page, 'geolocation')).toBe('prompt');
|
||||
expect(await getPermission(otherPage, 'geolocation')).toBe('granted');
|
||||
await context.clearPermissionOverrides();
|
||||
expect(await getPermission(page, 'geolocation')).toBe('prompt');
|
||||
expect(await getPermission(otherPage, 'geolocation')).toBe('granted');
|
||||
|
||||
await otherContext.close();
|
||||
}
|
||||
);
|
||||
itFailsFirefox('should grant persistent-storage', async () => {
|
||||
await otherContext.close();
|
||||
});
|
||||
it('should grant persistent-storage', async () => {
|
||||
const {page, server, context} = getTestState();
|
||||
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
@ -475,7 +471,7 @@ describe('Page', function () {
|
||||
});
|
||||
|
||||
describe('Page.setGeolocation', function () {
|
||||
itFailsFirefox('should work', async () => {
|
||||
it('should work', async () => {
|
||||
const {page, server, context} = getTestState();
|
||||
|
||||
await context.overridePermissions(server.PREFIX, ['geolocation']);
|
||||
@ -509,7 +505,7 @@ describe('Page', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describeFailsFirefox('Page.setOfflineMode', function () {
|
||||
describe('Page.setOfflineMode', function () {
|
||||
it('should work', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
@ -547,7 +543,7 @@ describe('Page', function () {
|
||||
});
|
||||
|
||||
describe('ExecutionContext.queryObjects', function () {
|
||||
itFailsFirefox('should work', async () => {
|
||||
it('should work', async () => {
|
||||
const {page} = getTestState();
|
||||
|
||||
// Instantiate an object
|
||||
@ -567,7 +563,7 @@ describe('Page', function () {
|
||||
}, objectsHandle);
|
||||
expect(values).toEqual(['hello', 'world']);
|
||||
});
|
||||
itFailsFirefox('should work for non-blank page', async () => {
|
||||
it('should work for non-blank page', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
// Instantiate an object
|
||||
@ -613,7 +609,7 @@ describe('Page', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describeFailsFirefox('Page.Events.Console', function () {
|
||||
describe('Page.Events.Console', function () {
|
||||
it('should work', async () => {
|
||||
const {page} = getTestState();
|
||||
|
||||
@ -802,7 +798,7 @@ describe('Page', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describeFailsFirefox('Page.metrics', function () {
|
||||
describe('Page.metrics', function () {
|
||||
it('should get metrics from a page', async () => {
|
||||
const {page} = getTestState();
|
||||
|
||||
@ -1108,7 +1104,7 @@ describe('Page', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describeFailsFirefox('Page.exposeFunction', function () {
|
||||
describe('Page.exposeFunction', function () {
|
||||
it('should work', async () => {
|
||||
const {page} = getTestState();
|
||||
|
||||
@ -1266,7 +1262,7 @@ describe('Page', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describeFailsFirefox('Page.Events.PageError', function () {
|
||||
describe('Page.Events.PageError', function () {
|
||||
it('should fire', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
@ -1329,7 +1325,7 @@ describe('Page', function () {
|
||||
})
|
||||
).toContain('iPhone');
|
||||
});
|
||||
itFailsFirefox('should work with additional userAgentMetdata', async () => {
|
||||
it('should work with additional userAgentMetdata', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
await page.setUserAgent('MockBrowser', {
|
||||
@ -1496,7 +1492,7 @@ describe('Page', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describeFailsFirefox('Page.setBypassCSP', function () {
|
||||
describe('Page.setBypassCSP', function () {
|
||||
it('should bypass CSP meta tag', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
@ -1879,21 +1875,18 @@ describe('Page', function () {
|
||||
).toBe('rgb(0, 128, 0)');
|
||||
});
|
||||
|
||||
itFailsFirefox(
|
||||
'should throw when added with content to the CSP page',
|
||||
async () => {
|
||||
const {page, server} = getTestState();
|
||||
it('should throw when added with content to the CSP page', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
await page.goto(server.PREFIX + '/csp.html');
|
||||
let error!: Error;
|
||||
await page
|
||||
.addStyleTag({content: 'body { background-color: green; }'})
|
||||
.catch(error_ => {
|
||||
return (error = error_);
|
||||
});
|
||||
expect(error).toBeTruthy();
|
||||
}
|
||||
);
|
||||
await page.goto(server.PREFIX + '/csp.html');
|
||||
let error!: Error;
|
||||
await page
|
||||
.addStyleTag({content: 'body { background-color: green; }'})
|
||||
.catch(error_ => {
|
||||
return (error = error_);
|
||||
});
|
||||
expect(error).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should throw when added with URL to the CSP page', async () => {
|
||||
const {page, server} = getTestState();
|
||||
@ -1921,7 +1914,7 @@ describe('Page', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describeFailsFirefox('Page.setJavaScriptEnabled', function () {
|
||||
describe('Page.setJavaScriptEnabled', function () {
|
||||
it('should work', async () => {
|
||||
const {page} = getTestState();
|
||||
|
||||
@ -1962,23 +1955,20 @@ describe('Page', function () {
|
||||
]);
|
||||
expect(nonCachedRequest.headers['if-modified-since']).toBe(undefined);
|
||||
});
|
||||
itFailsFirefox(
|
||||
'should stay disabled when toggling request interception on/off',
|
||||
async () => {
|
||||
const {page, server} = getTestState();
|
||||
it('should stay disabled when toggling request interception on/off', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
await page.setCacheEnabled(false);
|
||||
await page.setRequestInterception(true);
|
||||
await page.setRequestInterception(false);
|
||||
await page.setCacheEnabled(false);
|
||||
await page.setRequestInterception(true);
|
||||
await page.setRequestInterception(false);
|
||||
|
||||
await page.goto(server.PREFIX + '/cached/one-style.html');
|
||||
const [nonCachedRequest] = await Promise.all([
|
||||
server.waitForRequest('/cached/one-style.html'),
|
||||
page.reload(),
|
||||
]);
|
||||
expect(nonCachedRequest.headers['if-modified-since']).toBe(undefined);
|
||||
}
|
||||
);
|
||||
await page.goto(server.PREFIX + '/cached/one-style.html');
|
||||
const [nonCachedRequest] = await Promise.all([
|
||||
server.waitForRequest('/cached/one-style.html'),
|
||||
page.reload(),
|
||||
]);
|
||||
expect(nonCachedRequest.headers['if-modified-since']).toBe(undefined);
|
||||
});
|
||||
});
|
||||
|
||||
describe('printing to PDF', function () {
|
||||
@ -2220,33 +2210,30 @@ describe('Page', function () {
|
||||
expect(error.message).toContain('Values must be strings');
|
||||
});
|
||||
// @see https://github.com/puppeteer/puppeteer/issues/3327
|
||||
itFailsFirefox(
|
||||
'should work when re-defining top-level Event class',
|
||||
async () => {
|
||||
const {page, server} = getTestState();
|
||||
it('should work when re-defining top-level Event class', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
await page.goto(server.PREFIX + '/input/select.html');
|
||||
await page.goto(server.PREFIX + '/input/select.html');
|
||||
await page.evaluate(() => {
|
||||
// @ts-expect-error Expected.
|
||||
return (window.Event = undefined);
|
||||
});
|
||||
await page.select('select', 'blue');
|
||||
expect(
|
||||
await page.evaluate(() => {
|
||||
// @ts-expect-error Expected.
|
||||
return (window.Event = undefined);
|
||||
});
|
||||
await page.select('select', 'blue');
|
||||
expect(
|
||||
await page.evaluate(() => {
|
||||
return (globalThis as any).result.onInput;
|
||||
})
|
||||
).toEqual(['blue']);
|
||||
expect(
|
||||
await page.evaluate(() => {
|
||||
return (globalThis as any).result.onChange;
|
||||
})
|
||||
).toEqual(['blue']);
|
||||
}
|
||||
);
|
||||
return (globalThis as any).result.onInput;
|
||||
})
|
||||
).toEqual(['blue']);
|
||||
expect(
|
||||
await page.evaluate(() => {
|
||||
return (globalThis as any).result.onChange;
|
||||
})
|
||||
).toEqual(['blue']);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Page.Events.Close', function () {
|
||||
itFailsFirefox('should work with window.close', async () => {
|
||||
it('should work with window.close', async () => {
|
||||
const {page, context} = getTestState();
|
||||
|
||||
const newPagePromise = new Promise<Page>(fulfill => {
|
||||
|
@ -17,15 +17,12 @@
|
||||
import expect from 'expect';
|
||||
import http from 'http';
|
||||
import os from 'os';
|
||||
import {
|
||||
getTestState,
|
||||
describeFailsFirefox,
|
||||
itFailsWindows,
|
||||
} from './mocha-utils.js';
|
||||
import {getTestState} from './mocha-utils.js';
|
||||
import type {Server, IncomingMessage, ServerResponse} from 'http';
|
||||
import type {Browser} from '../../lib/cjs/puppeteer/common/Browser.js';
|
||||
import type {AddressInfo} from 'net';
|
||||
import {TestServer} from '../../utils/testserver/lib/index.js';
|
||||
import {it} from './mocha-utils.js';
|
||||
|
||||
let HOSTNAME = os.hostname();
|
||||
|
||||
@ -53,7 +50,7 @@ function getEmptyPageUrl(server: TestServer): string {
|
||||
return `http://${HOSTNAME}:${server.PORT}${emptyPagePath}`;
|
||||
}
|
||||
|
||||
describeFailsFirefox('request proxy', () => {
|
||||
describe('request proxy', () => {
|
||||
let browser: Browser;
|
||||
let proxiedRequestUrls: string[];
|
||||
let proxyServer: Server;
|
||||
@ -194,28 +191,25 @@ describeFailsFirefox('request proxy', () => {
|
||||
/**
|
||||
* See issues #7873, #7719, and #7698.
|
||||
*/
|
||||
itFailsWindows(
|
||||
'should proxy requests when configured at context level',
|
||||
async () => {
|
||||
const {puppeteer, defaultBrowserOptions, server} = getTestState();
|
||||
const emptyPageUrl = getEmptyPageUrl(server);
|
||||
it('should proxy requests when configured at context level', async () => {
|
||||
const {puppeteer, defaultBrowserOptions, server} = getTestState();
|
||||
const emptyPageUrl = getEmptyPageUrl(server);
|
||||
|
||||
browser = await puppeteer.launch({
|
||||
...defaultBrowserOptions,
|
||||
args: defaultArgs,
|
||||
});
|
||||
browser = await puppeteer.launch({
|
||||
...defaultBrowserOptions,
|
||||
args: defaultArgs,
|
||||
});
|
||||
|
||||
const context = await browser.createIncognitoBrowserContext({
|
||||
proxyServer: proxyServerUrl,
|
||||
});
|
||||
const page = await context.newPage();
|
||||
const response = (await page.goto(emptyPageUrl))!;
|
||||
const context = await browser.createIncognitoBrowserContext({
|
||||
proxyServer: proxyServerUrl,
|
||||
});
|
||||
const page = await context.newPage();
|
||||
const response = (await page.goto(emptyPageUrl))!;
|
||||
|
||||
expect(response.ok()).toBe(true);
|
||||
expect(response.ok()).toBe(true);
|
||||
|
||||
expect(proxiedRequestUrls).toEqual([emptyPageUrl]);
|
||||
}
|
||||
);
|
||||
expect(proxiedRequestUrls).toEqual([emptyPageUrl]);
|
||||
});
|
||||
|
||||
it('should respect proxy bypass list when configured at context level', async () => {
|
||||
const {puppeteer, defaultBrowserOptions, server} = getTestState();
|
||||
|
@ -20,6 +20,7 @@ import {
|
||||
setupTestBrowserHooks,
|
||||
setupTestPageAndContextHooks,
|
||||
} from './mocha-utils.js';
|
||||
import {it} from './mocha-utils.js';
|
||||
|
||||
describe('Query handler tests', function () {
|
||||
setupTestBrowserHooks();
|
||||
|
@ -20,6 +20,7 @@ import {
|
||||
setupTestBrowserHooks,
|
||||
setupTestPageAndContextHooks,
|
||||
} from './mocha-utils.js';
|
||||
import {it} from './mocha-utils.js';
|
||||
|
||||
describe('querySelector', function () {
|
||||
setupTestBrowserHooks();
|
||||
|
@ -22,7 +22,6 @@ import {
|
||||
getTestState,
|
||||
setupTestBrowserHooks,
|
||||
setupTestPageAndContextHooks,
|
||||
describeFailsFirefox,
|
||||
} from './mocha-utils.js';
|
||||
import {ConsoleMessage} from '../../lib/cjs/puppeteer/common/ConsoleMessage.js';
|
||||
import {
|
||||
@ -30,11 +29,12 @@ import {
|
||||
HTTPRequest,
|
||||
InterceptResolutionAction,
|
||||
} from '../../lib/cjs/puppeteer/common/HTTPRequest.js';
|
||||
import {it} from './mocha-utils.js';
|
||||
|
||||
describe('request interception', function () {
|
||||
setupTestBrowserHooks();
|
||||
setupTestPageAndContextHooks();
|
||||
describeFailsFirefox('Page.setRequestInterception', function () {
|
||||
describe('Page.setRequestInterception', function () {
|
||||
const expectedActions: ActionResult[] = ['abort', 'continue', 'respond'];
|
||||
while (expectedActions.length > 0) {
|
||||
const expectedAction = expectedActions.pop();
|
||||
@ -709,7 +709,7 @@ describe('request interception', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describeFailsFirefox('Request.continue', function () {
|
||||
describe('Request.continue', function () {
|
||||
it('should work', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
@ -805,7 +805,7 @@ describe('request interception', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describeFailsFirefox('Request.respond', function () {
|
||||
describe('Request.respond', function () {
|
||||
it('should work', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
|
@ -22,15 +22,15 @@ import {
|
||||
getTestState,
|
||||
setupTestBrowserHooks,
|
||||
setupTestPageAndContextHooks,
|
||||
describeFailsFirefox,
|
||||
} from './mocha-utils.js';
|
||||
import {HTTPRequest} from '../../lib/cjs/puppeteer/common/HTTPRequest.js';
|
||||
import {ConsoleMessage} from '../../lib/cjs/puppeteer/common/ConsoleMessage.js';
|
||||
import {it} from './mocha-utils.js';
|
||||
|
||||
describe('request interception', function () {
|
||||
setupTestBrowserHooks();
|
||||
setupTestPageAndContextHooks();
|
||||
describeFailsFirefox('Page.setRequestInterception', function () {
|
||||
describe('Page.setRequestInterception', function () {
|
||||
it('should intercept', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
@ -623,7 +623,7 @@ describe('request interception', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describeFailsFirefox('Request.continue', function () {
|
||||
describe('Request.continue', function () {
|
||||
it('should work', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
@ -739,7 +739,7 @@ describe('request interception', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describeFailsFirefox('Request.respond', function () {
|
||||
describe('Request.respond', function () {
|
||||
it('should work', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
|
@ -19,17 +19,15 @@ import {
|
||||
getTestState,
|
||||
setupTestBrowserHooks,
|
||||
setupTestPageAndContextHooks,
|
||||
itFailsFirefox,
|
||||
itHeadfulOnly,
|
||||
itChromeOnly,
|
||||
} from './mocha-utils.js';
|
||||
import {it} from './mocha-utils.js';
|
||||
|
||||
describe('Screenshots', function () {
|
||||
setupTestBrowserHooks();
|
||||
setupTestPageAndContextHooks();
|
||||
|
||||
describe('Page.screenshot', function () {
|
||||
itFailsFirefox('should work', async () => {
|
||||
it('should work', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
await page.setViewport({width: 500, height: 500});
|
||||
@ -37,7 +35,7 @@ describe('Screenshots', function () {
|
||||
const screenshot = await page.screenshot();
|
||||
expect(screenshot).toBeGolden('screenshot-sanity.png');
|
||||
});
|
||||
itFailsFirefox('should clip rect', async () => {
|
||||
it('should clip rect', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
await page.setViewport({width: 500, height: 500});
|
||||
@ -52,7 +50,7 @@ describe('Screenshots', function () {
|
||||
});
|
||||
expect(screenshot).toBeGolden('screenshot-clip-rect.png');
|
||||
});
|
||||
itFailsFirefox('should use scale for clip', async () => {
|
||||
it('should use scale for clip', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
await page.setViewport({width: 500, height: 500});
|
||||
@ -68,23 +66,20 @@ describe('Screenshots', function () {
|
||||
});
|
||||
expect(screenshot).toBeGolden('screenshot-clip-rect-scale2.png');
|
||||
});
|
||||
itFailsFirefox(
|
||||
'should get screenshot bigger than the viewport',
|
||||
async () => {
|
||||
const {page, server} = getTestState();
|
||||
await page.setViewport({width: 50, height: 50});
|
||||
await page.goto(server.PREFIX + '/grid.html');
|
||||
const screenshot = await page.screenshot({
|
||||
clip: {
|
||||
x: 25,
|
||||
y: 25,
|
||||
width: 100,
|
||||
height: 100,
|
||||
},
|
||||
});
|
||||
expect(screenshot).toBeGolden('screenshot-offscreen-clip.png');
|
||||
}
|
||||
);
|
||||
it('should get screenshot bigger than the viewport', async () => {
|
||||
const {page, server} = getTestState();
|
||||
await page.setViewport({width: 50, height: 50});
|
||||
await page.goto(server.PREFIX + '/grid.html');
|
||||
const screenshot = await page.screenshot({
|
||||
clip: {
|
||||
x: 25,
|
||||
y: 25,
|
||||
width: 100,
|
||||
height: 100,
|
||||
},
|
||||
});
|
||||
expect(screenshot).toBeGolden('screenshot-offscreen-clip.png');
|
||||
});
|
||||
it('should run in parallel', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
@ -106,7 +101,7 @@ describe('Screenshots', function () {
|
||||
const screenshots = await Promise.all(promises);
|
||||
expect(screenshots[1]!).toBeGolden('grid-cell-1.png');
|
||||
});
|
||||
itFailsFirefox('should take fullPage screenshots', async () => {
|
||||
it('should take fullPage screenshots', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
await page.setViewport({width: 500, height: 500});
|
||||
@ -147,7 +142,7 @@ describe('Screenshots', function () {
|
||||
})
|
||||
);
|
||||
});
|
||||
itFailsFirefox('should allow transparency', async () => {
|
||||
it('should allow transparency', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
await page.setViewport({width: 100, height: 100});
|
||||
@ -155,7 +150,7 @@ describe('Screenshots', function () {
|
||||
const screenshot = await page.screenshot({omitBackground: true});
|
||||
expect(screenshot).toBeGolden('transparent.png');
|
||||
});
|
||||
itFailsFirefox('should render white background on jpeg file', async () => {
|
||||
it('should render white background on jpeg file', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
await page.setViewport({width: 100, height: 100});
|
||||
@ -166,7 +161,7 @@ describe('Screenshots', function () {
|
||||
});
|
||||
expect(screenshot).toBeGolden('white.jpg');
|
||||
});
|
||||
itFailsFirefox('should work with webp', async () => {
|
||||
it('should work with webp', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
await page.setViewport({width: 100, height: 100});
|
||||
@ -190,7 +185,7 @@ describe('Screenshots', function () {
|
||||
});
|
||||
expect(screenshot).toBeGolden('screenshot-clip-odd-size.png');
|
||||
});
|
||||
itFailsFirefox('should return base64', async () => {
|
||||
it('should return base64', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
await page.setViewport({width: 500, height: 500});
|
||||
@ -206,7 +201,7 @@ describe('Screenshots', function () {
|
||||
'screenshot-sanity.png'
|
||||
);
|
||||
});
|
||||
itHeadfulOnly('should work in "fromSurface: false" mode', async () => {
|
||||
it('should work in "fromSurface: false" mode', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
await page.setViewport({width: 500, height: 500});
|
||||
@ -231,7 +226,7 @@ describe('Screenshots', function () {
|
||||
const screenshot = await elementHandle.screenshot();
|
||||
expect(screenshot).toBeGolden('screenshot-element-bounding-box.png');
|
||||
});
|
||||
itChromeOnly('should work with a null viewport', async () => {
|
||||
it('should work with a null viewport', async () => {
|
||||
const {defaultBrowserOptions, puppeteer, server} = getTestState();
|
||||
|
||||
const browser = await puppeteer.launch({
|
||||
@ -271,14 +266,12 @@ describe('Screenshots', function () {
|
||||
const screenshot = await elementHandle.screenshot();
|
||||
expect(screenshot).toBeGolden('screenshot-element-padding-border.png');
|
||||
});
|
||||
itFailsFirefox(
|
||||
'should capture full element when larger than viewport',
|
||||
async () => {
|
||||
const {page} = getTestState();
|
||||
it('should capture full element when larger than viewport', async () => {
|
||||
const {page} = getTestState();
|
||||
|
||||
await page.setViewport({width: 500, height: 500});
|
||||
await page.setViewport({width: 500, height: 500});
|
||||
|
||||
await page.setContent(`
|
||||
await page.setContent(`
|
||||
something above
|
||||
<style>
|
||||
div.to-screenshot {
|
||||
@ -293,22 +286,21 @@ describe('Screenshots', function () {
|
||||
</style>
|
||||
<div class="to-screenshot"></div>
|
||||
`);
|
||||
const elementHandle = (await page.$('div.to-screenshot'))!;
|
||||
const screenshot = await elementHandle.screenshot();
|
||||
expect(screenshot).toBeGolden(
|
||||
'screenshot-element-larger-than-viewport.png'
|
||||
);
|
||||
const elementHandle = (await page.$('div.to-screenshot'))!;
|
||||
const screenshot = await elementHandle.screenshot();
|
||||
expect(screenshot).toBeGolden(
|
||||
'screenshot-element-larger-than-viewport.png'
|
||||
);
|
||||
|
||||
expect(
|
||||
await page.evaluate(() => {
|
||||
return {
|
||||
w: window.innerWidth,
|
||||
h: window.innerHeight,
|
||||
};
|
||||
})
|
||||
).toEqual({w: 500, h: 500});
|
||||
}
|
||||
);
|
||||
expect(
|
||||
await page.evaluate(() => {
|
||||
return {
|
||||
w: window.innerWidth,
|
||||
h: window.innerHeight,
|
||||
};
|
||||
})
|
||||
).toEqual({w: 500, h: 500});
|
||||
});
|
||||
it('should scroll element into view', async () => {
|
||||
const {page} = getTestState();
|
||||
|
||||
@ -336,7 +328,7 @@ describe('Screenshots', function () {
|
||||
'screenshot-element-scrolled-into-view.png'
|
||||
);
|
||||
});
|
||||
itFailsFirefox('should work with a rotated element', async () => {
|
||||
it('should work with a rotated element', async () => {
|
||||
const {page} = getTestState();
|
||||
|
||||
await page.setViewport({width: 500, height: 500});
|
||||
@ -351,7 +343,7 @@ describe('Screenshots', function () {
|
||||
const screenshot = await elementHandle.screenshot();
|
||||
expect(screenshot).toBeGolden('screenshot-element-rotate.png');
|
||||
});
|
||||
itFailsFirefox('should fail to screenshot a detached element', async () => {
|
||||
it('should fail to screenshot a detached element', async () => {
|
||||
const {page} = getTestState();
|
||||
|
||||
await page.setContent('<h1>remove this</h1>');
|
||||
@ -386,7 +378,7 @@ describe('Screenshots', function () {
|
||||
const screenshot = await elementHandle.screenshot();
|
||||
expect(screenshot).toBeGolden('screenshot-element-fractional.png');
|
||||
});
|
||||
itFailsFirefox('should work for an element with an offset', async () => {
|
||||
it('should work for an element with an offset', async () => {
|
||||
const {page} = getTestState();
|
||||
|
||||
await page.setContent(
|
||||
|
@ -20,11 +20,12 @@ import {Page} from '../../lib/cjs/puppeteer/common/Page.js';
|
||||
import {Target} from '../../lib/cjs/puppeteer/common/Target.js';
|
||||
import {
|
||||
getTestState,
|
||||
itFailsFirefox,
|
||||
setupTestBrowserHooks,
|
||||
setupTestPageAndContextHooks,
|
||||
} from './mocha-utils.js';
|
||||
import utils from './utils.js';
|
||||
import {it} from './mocha-utils.js';
|
||||
|
||||
const {waitEvent} = utils;
|
||||
|
||||
describe('Target', function () {
|
||||
@ -79,7 +80,7 @@ describe('Target', function () {
|
||||
).toBe('Hello world');
|
||||
expect(await originalPage.$('body')).toBeTruthy();
|
||||
});
|
||||
itFailsFirefox('should be able to use async waitForTarget', async () => {
|
||||
it('should be able to use async waitForTarget', async () => {
|
||||
const {page, server, context} = getTestState();
|
||||
|
||||
const [otherPage] = await Promise.all([
|
||||
@ -101,89 +102,83 @@ describe('Target', function () {
|
||||
);
|
||||
expect(page).not.toEqual(otherPage);
|
||||
});
|
||||
itFailsFirefox(
|
||||
'should report when a new page is created and closed',
|
||||
async () => {
|
||||
const {page, server, context} = getTestState();
|
||||
it('should report when a new page is created and closed', async () => {
|
||||
const {page, server, context} = getTestState();
|
||||
|
||||
const [otherPage] = await Promise.all([
|
||||
context
|
||||
.waitForTarget(target => {
|
||||
return target.url() === server.CROSS_PROCESS_PREFIX + '/empty.html';
|
||||
})
|
||||
.then(target => {
|
||||
return target.page();
|
||||
}),
|
||||
page.evaluate((url: string) => {
|
||||
return window.open(url);
|
||||
}, server.CROSS_PROCESS_PREFIX + '/empty.html'),
|
||||
]);
|
||||
expect(otherPage!.url()).toContain(server.CROSS_PROCESS_PREFIX);
|
||||
expect(
|
||||
await otherPage!.evaluate(() => {
|
||||
return ['Hello', 'world'].join(' ');
|
||||
const [otherPage] = await Promise.all([
|
||||
context
|
||||
.waitForTarget(target => {
|
||||
return target.url() === server.CROSS_PROCESS_PREFIX + '/empty.html';
|
||||
})
|
||||
).toBe('Hello world');
|
||||
expect(await otherPage!.$('body')).toBeTruthy();
|
||||
|
||||
let allPages = await context.pages();
|
||||
expect(allPages).toContain(page);
|
||||
expect(allPages).toContain(otherPage);
|
||||
|
||||
const closePagePromise = new Promise(fulfill => {
|
||||
return context.once('targetdestroyed', target => {
|
||||
return fulfill(target.page());
|
||||
});
|
||||
});
|
||||
await otherPage!.close();
|
||||
expect(await closePagePromise).toBe(otherPage);
|
||||
|
||||
allPages = (await Promise.all(
|
||||
context.targets().map(target => {
|
||||
.then(target => {
|
||||
return target.page();
|
||||
})
|
||||
)) as Page[];
|
||||
expect(allPages).toContain(page);
|
||||
expect(allPages).not.toContain(otherPage);
|
||||
}
|
||||
);
|
||||
itFailsFirefox(
|
||||
'should report when a service worker is created and destroyed',
|
||||
async () => {
|
||||
const {page, server, context} = getTestState();
|
||||
}),
|
||||
page.evaluate((url: string) => {
|
||||
return window.open(url);
|
||||
}, server.CROSS_PROCESS_PREFIX + '/empty.html'),
|
||||
]);
|
||||
expect(otherPage!.url()).toContain(server.CROSS_PROCESS_PREFIX);
|
||||
expect(
|
||||
await otherPage!.evaluate(() => {
|
||||
return ['Hello', 'world'].join(' ');
|
||||
})
|
||||
).toBe('Hello world');
|
||||
expect(await otherPage!.$('body')).toBeTruthy();
|
||||
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
const createdTarget = new Promise<Target>(fulfill => {
|
||||
return context.once('targetcreated', target => {
|
||||
return fulfill(target);
|
||||
});
|
||||
let allPages = await context.pages();
|
||||
expect(allPages).toContain(page);
|
||||
expect(allPages).toContain(otherPage);
|
||||
|
||||
const closePagePromise = new Promise(fulfill => {
|
||||
return context.once('targetdestroyed', target => {
|
||||
return fulfill(target.page());
|
||||
});
|
||||
});
|
||||
await otherPage!.close();
|
||||
expect(await closePagePromise).toBe(otherPage);
|
||||
|
||||
await page.goto(server.PREFIX + '/serviceworkers/empty/sw.html');
|
||||
allPages = (await Promise.all(
|
||||
context.targets().map(target => {
|
||||
return target.page();
|
||||
})
|
||||
)) as Page[];
|
||||
expect(allPages).toContain(page);
|
||||
expect(allPages).not.toContain(otherPage);
|
||||
});
|
||||
it('should report when a service worker is created and destroyed', async () => {
|
||||
const {page, server, context} = getTestState();
|
||||
|
||||
expect((await createdTarget).type()).toBe('service_worker');
|
||||
expect((await createdTarget).url()).toBe(
|
||||
server.PREFIX + '/serviceworkers/empty/sw.js'
|
||||
);
|
||||
|
||||
const destroyedTarget = new Promise(fulfill => {
|
||||
return context.once('targetdestroyed', target => {
|
||||
return fulfill(target);
|
||||
});
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
const createdTarget = new Promise<Target>(fulfill => {
|
||||
return context.once('targetcreated', target => {
|
||||
return fulfill(target);
|
||||
});
|
||||
await page.evaluate(() => {
|
||||
return (
|
||||
globalThis as unknown as {
|
||||
registrationPromise: Promise<{unregister: () => void}>;
|
||||
}
|
||||
).registrationPromise.then((registration: any) => {
|
||||
return registration.unregister();
|
||||
});
|
||||
});
|
||||
|
||||
await page.goto(server.PREFIX + '/serviceworkers/empty/sw.html');
|
||||
|
||||
expect((await createdTarget).type()).toBe('service_worker');
|
||||
expect((await createdTarget).url()).toBe(
|
||||
server.PREFIX + '/serviceworkers/empty/sw.js'
|
||||
);
|
||||
|
||||
const destroyedTarget = new Promise(fulfill => {
|
||||
return context.once('targetdestroyed', target => {
|
||||
return fulfill(target);
|
||||
});
|
||||
expect(await destroyedTarget).toBe(await createdTarget);
|
||||
}
|
||||
);
|
||||
itFailsFirefox('should create a worker from a service worker', async () => {
|
||||
});
|
||||
await page.evaluate(() => {
|
||||
return (
|
||||
globalThis as unknown as {
|
||||
registrationPromise: Promise<{unregister: () => void}>;
|
||||
}
|
||||
).registrationPromise.then((registration: any) => {
|
||||
return registration.unregister();
|
||||
});
|
||||
});
|
||||
expect(await destroyedTarget).toBe(await createdTarget);
|
||||
});
|
||||
it('should create a worker from a service worker', async () => {
|
||||
const {page, server, context} = getTestState();
|
||||
|
||||
await page.goto(server.PREFIX + '/serviceworkers/empty/sw.html');
|
||||
@ -198,7 +193,7 @@ describe('Target', function () {
|
||||
})
|
||||
).toBe('[object ServiceWorkerGlobalScope]');
|
||||
});
|
||||
itFailsFirefox('should create a worker from a shared worker', async () => {
|
||||
it('should create a worker from a shared worker', async () => {
|
||||
const {page, server, context} = getTestState();
|
||||
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
@ -215,7 +210,7 @@ describe('Target', function () {
|
||||
})
|
||||
).toBe('[object SharedWorkerGlobalScope]');
|
||||
});
|
||||
itFailsFirefox('should report when a target url changes', async () => {
|
||||
it('should report when a target url changes', async () => {
|
||||
const {page, server, context} = getTestState();
|
||||
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
@ -235,7 +230,7 @@ describe('Target', function () {
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
expect((await changedTarget).url()).toBe(server.EMPTY_PAGE);
|
||||
});
|
||||
itFailsFirefox('should not report uninitialized pages', async () => {
|
||||
it('should not report uninitialized pages', async () => {
|
||||
const {context} = getTestState();
|
||||
|
||||
let targetChanged = false;
|
||||
@ -268,37 +263,34 @@ describe('Target', function () {
|
||||
expect(targetChanged).toBe(false);
|
||||
context.removeListener('targetchanged', listener);
|
||||
});
|
||||
itFailsFirefox(
|
||||
'should not crash while redirecting if original request was missed',
|
||||
async () => {
|
||||
const {page, server, context} = getTestState();
|
||||
it('should not crash while redirecting if original request was missed', async () => {
|
||||
const {page, server, context} = getTestState();
|
||||
|
||||
let serverResponse!: ServerResponse;
|
||||
server.setRoute('/one-style.css', (_req, res) => {
|
||||
return (serverResponse = res);
|
||||
});
|
||||
// Open a new page. Use window.open to connect to the page later.
|
||||
await Promise.all([
|
||||
page.evaluate((url: string) => {
|
||||
return window.open(url);
|
||||
}, server.PREFIX + '/one-style.html'),
|
||||
server.waitForRequest('/one-style.css'),
|
||||
]);
|
||||
// Connect to the opened page.
|
||||
const target = await context.waitForTarget(target => {
|
||||
return target.url().includes('one-style.html');
|
||||
});
|
||||
const newPage = (await target.page())!;
|
||||
// Issue a redirect.
|
||||
serverResponse.writeHead(302, {location: '/injectedstyle.css'});
|
||||
serverResponse.end();
|
||||
// Wait for the new page to load.
|
||||
await waitEvent(newPage, 'load');
|
||||
// Cleanup.
|
||||
await newPage.close();
|
||||
}
|
||||
);
|
||||
itFailsFirefox('should have an opener', async () => {
|
||||
let serverResponse!: ServerResponse;
|
||||
server.setRoute('/one-style.css', (_req, res) => {
|
||||
return (serverResponse = res);
|
||||
});
|
||||
// Open a new page. Use window.open to connect to the page later.
|
||||
await Promise.all([
|
||||
page.evaluate((url: string) => {
|
||||
return window.open(url);
|
||||
}, server.PREFIX + '/one-style.html'),
|
||||
server.waitForRequest('/one-style.css'),
|
||||
]);
|
||||
// Connect to the opened page.
|
||||
const target = await context.waitForTarget(target => {
|
||||
return target.url().includes('one-style.html');
|
||||
});
|
||||
const newPage = (await target.page())!;
|
||||
// Issue a redirect.
|
||||
serverResponse.writeHead(302, {location: '/injectedstyle.css'});
|
||||
serverResponse.end();
|
||||
// Wait for the new page to load.
|
||||
await waitEvent(newPage, 'load');
|
||||
// Cleanup.
|
||||
await newPage.close();
|
||||
});
|
||||
it('should have an opener', async () => {
|
||||
const {page, server, context} = getTestState();
|
||||
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
@ -318,7 +310,7 @@ describe('Target', function () {
|
||||
});
|
||||
|
||||
describe('Browser.waitForTarget', () => {
|
||||
itFailsFirefox('should wait for a target', async () => {
|
||||
it('should wait for a target', async () => {
|
||||
const {browser, puppeteer, server} = getTestState();
|
||||
|
||||
let resolved = false;
|
||||
|
@ -19,10 +19,10 @@ import {
|
||||
getTestState,
|
||||
setupTestBrowserHooks,
|
||||
setupTestPageAndContextHooks,
|
||||
describeFailsFirefox,
|
||||
} from './mocha-utils.js';
|
||||
import {it} from './mocha-utils.js';
|
||||
|
||||
describeFailsFirefox('Touchscreen', function () {
|
||||
describe('Touchscreen', function () {
|
||||
setupTestBrowserHooks();
|
||||
setupTestPageAndContextHooks();
|
||||
|
||||
|
@ -17,11 +17,12 @@
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import expect from 'expect';
|
||||
import {getTestState, describeChromeOnly} from './mocha-utils.js';
|
||||
import {getTestState} from './mocha-utils.js';
|
||||
import {Browser} from '../../lib/cjs/puppeteer/common/Browser.js';
|
||||
import {Page} from '../../lib/cjs/puppeteer/common/Page.js';
|
||||
import {it} from './mocha-utils.js';
|
||||
|
||||
describeChromeOnly('Tracing', function () {
|
||||
describe('Tracing', function () {
|
||||
let outputFile!: string;
|
||||
let browser!: Browser;
|
||||
let page!: Page;
|
||||
|
@ -18,11 +18,11 @@ import expect from 'expect';
|
||||
import {isErrorLike} from '../../lib/cjs/puppeteer/util/ErrorLike.js';
|
||||
import {
|
||||
getTestState,
|
||||
itFailsFirefox,
|
||||
setupTestBrowserHooks,
|
||||
setupTestPageAndContextHooks,
|
||||
} from './mocha-utils.js';
|
||||
import {attachFrame, detachFrame} from './utils.js';
|
||||
import {it} from './mocha-utils.js';
|
||||
|
||||
describe('waittask specs', function () {
|
||||
setupTestBrowserHooks();
|
||||
@ -188,7 +188,7 @@ describe('waittask specs', function () {
|
||||
});
|
||||
await watchdog;
|
||||
});
|
||||
itFailsFirefox('should work with strict CSP policy', async () => {
|
||||
it('should work with strict CSP policy', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
server.setCSP('/empty.html', 'script-src ' + server.PREFIX);
|
||||
@ -421,7 +421,7 @@ describe('waittask specs', function () {
|
||||
await frame.waitForSelector('div');
|
||||
});
|
||||
|
||||
itFailsFirefox('should work with removed MutationObserver', async () => {
|
||||
it('should work with removed MutationObserver', async () => {
|
||||
const {page} = getTestState();
|
||||
|
||||
await page.evaluate(() => {
|
||||
@ -465,23 +465,20 @@ describe('waittask specs', function () {
|
||||
await watchdog;
|
||||
});
|
||||
|
||||
itFailsFirefox(
|
||||
'Page.waitForSelector is shortcut for main frame',
|
||||
async () => {
|
||||
const {page, server} = getTestState();
|
||||
it('Page.waitForSelector is shortcut for main frame', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
await attachFrame(page, 'frame1', server.EMPTY_PAGE);
|
||||
const otherFrame = page.frames()[1]!;
|
||||
const watchdog = page.waitForSelector('div');
|
||||
await otherFrame.evaluate(addElement, 'div');
|
||||
await page.evaluate(addElement, 'div');
|
||||
const eHandle = await watchdog;
|
||||
expect(eHandle?.frame).toBe(page.mainFrame());
|
||||
}
|
||||
);
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
await attachFrame(page, 'frame1', server.EMPTY_PAGE);
|
||||
const otherFrame = page.frames()[1]!;
|
||||
const watchdog = page.waitForSelector('div');
|
||||
await otherFrame.evaluate(addElement, 'div');
|
||||
await page.evaluate(addElement, 'div');
|
||||
const eHandle = await watchdog;
|
||||
expect(eHandle?.frame).toBe(page.mainFrame());
|
||||
});
|
||||
|
||||
itFailsFirefox('should run in specified frame', async () => {
|
||||
it('should run in specified frame', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
await attachFrame(page, 'frame1', server.EMPTY_PAGE);
|
||||
@ -495,7 +492,7 @@ describe('waittask specs', function () {
|
||||
expect(eHandle?.frame).toBe(frame2);
|
||||
});
|
||||
|
||||
itFailsFirefox('should throw when frame is detached', async () => {
|
||||
it('should throw when frame is detached', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
await attachFrame(page, 'frame1', server.EMPTY_PAGE);
|
||||
@ -738,7 +735,7 @@ describe('waittask specs', function () {
|
||||
'waiting for selector `.//div` failed: timeout 10ms exceeded'
|
||||
);
|
||||
});
|
||||
itFailsFirefox('should run in specified frame', async () => {
|
||||
it('should run in specified frame', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
await attachFrame(page, 'frame1', server.EMPTY_PAGE);
|
||||
@ -751,7 +748,7 @@ describe('waittask specs', function () {
|
||||
const eHandle = await waitForXPathPromise;
|
||||
expect(eHandle?.frame).toBe(frame2);
|
||||
});
|
||||
itFailsFirefox('should throw when frame is detached', async () => {
|
||||
it('should throw when frame is detached', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
||||
await attachFrame(page, 'frame1', server.EMPTY_PAGE);
|
||||
|
@ -18,14 +18,14 @@ import expect from 'expect';
|
||||
import {ConsoleMessage} from '../../lib/cjs/puppeteer/common/ConsoleMessage.js';
|
||||
import {WebWorker} from '../../lib/cjs/puppeteer/common/WebWorker.js';
|
||||
import {
|
||||
describeFailsFirefox,
|
||||
getTestState,
|
||||
setupTestBrowserHooks,
|
||||
setupTestPageAndContextHooks,
|
||||
} from './mocha-utils.js';
|
||||
import {waitEvent} from './utils.js';
|
||||
import {it} from './mocha-utils.js';
|
||||
|
||||
describeFailsFirefox('Workers', function () {
|
||||
describe('Workers', function () {
|
||||
setupTestBrowserHooks();
|
||||
setupTestPageAndContextHooks();
|
||||
it('Page.workers', async () => {
|
||||
|
@ -9,7 +9,8 @@
|
||||
},
|
||||
"include": ["src"],
|
||||
"references": [
|
||||
{"path": "../tsconfig.lib.json"},
|
||||
{"path": "../utils/testserver/tsconfig.json"}
|
||||
{"path": "../src/tsconfig.cjs.json"},
|
||||
{"path": "../utils/testserver/tsconfig.json"},
|
||||
{"path": "../utils/mochaRunner/tsconfig.json"}
|
||||
]
|
||||
}
|
||||
|
47
utils/mochaRunner/README.md
Normal file
47
utils/mochaRunner/README.md
Normal file
@ -0,0 +1,47 @@
|
||||
# Mocha Runner
|
||||
|
||||
Mocha Runner is a test runner on top of mocha. It uses `/test/TestSuites.json` and `/test/TestExpectations.json` files to run mocha tests in multiple configurations and interpret results.
|
||||
|
||||
## Running tests for Mocha Runner itself.
|
||||
|
||||
```
|
||||
npm run build:dev && npx c8 node utils/mochaRunner/lib/test.js
|
||||
```
|
||||
|
||||
## Running tests using Mocha Runner
|
||||
|
||||
```
|
||||
npm run build:dev && npm run test
|
||||
```
|
||||
|
||||
By default, the runner runs all test suites applicable to the current platform.
|
||||
To pick a test suite, provide the `--test-suite` arguments. For example,
|
||||
|
||||
```
|
||||
npm run build:dev && npm run test -- --test-suite chrome-headless
|
||||
```
|
||||
|
||||
## TestSuites.json
|
||||
|
||||
Define test suites via the `testSuites` attribute. `parameters` can be used in the `TestExpectations.json` to disable tests
|
||||
based on parameters. The meaning for parameters is defined in `parameterDefinitons` which tell what env object corresponds
|
||||
to the given parameter.
|
||||
|
||||
## TestExpectations.json
|
||||
|
||||
An expectation looks like this:
|
||||
|
||||
```
|
||||
{
|
||||
"testIdPattern": "[accessibility.spec]",
|
||||
"platforms": ["darwin", "win32", "linux"],
|
||||
"parameters": ["firefox"],
|
||||
"expectations": ["SKIP"]
|
||||
}
|
||||
```
|
||||
|
||||
`testIdPattern` defines a string that will be used to prefix-match tests. `platforms` defines the platforms the expectation is for (`or`-logic).
|
||||
`parameters` defines the parameters that the test has to match (`and`-logic). `expectations` is the list of test results that are considered to be acceptable.
|
||||
|
||||
Currently, expectations are updated manually. The test runner outputs the suggested changes to the expectation file if the test run does not match
|
||||
expectations.
|
204
utils/mochaRunner/src/main.ts
Normal file
204
utils/mochaRunner/src/main.ts
Normal file
@ -0,0 +1,204 @@
|
||||
import {
|
||||
TestExpectation,
|
||||
MochaResults,
|
||||
zTestSuiteFile,
|
||||
zPlatform,
|
||||
TestSuite,
|
||||
TestSuiteFile,
|
||||
Platform,
|
||||
} from './types.js';
|
||||
|
||||
import path from 'path';
|
||||
import fs from 'fs';
|
||||
import os from 'os';
|
||||
import {spawn} from 'node:child_process';
|
||||
import {
|
||||
extendProcessEnv,
|
||||
filterByPlatform,
|
||||
prettyPrintJSON,
|
||||
readJSON,
|
||||
filterByParameters,
|
||||
getExpectationUpdates,
|
||||
getSkippedTests,
|
||||
} from './utils.js';
|
||||
|
||||
function getApplicableTestSuites(
|
||||
parsedSuitesFile: TestSuiteFile,
|
||||
platform: Platform
|
||||
): TestSuite[] {
|
||||
const testSuiteArgIdx = process.argv.indexOf('--test-suite');
|
||||
let applicableSuites: TestSuite[] = [];
|
||||
|
||||
if (testSuiteArgIdx === -1) {
|
||||
applicableSuites = filterByPlatform(parsedSuitesFile.testSuites, platform);
|
||||
} else {
|
||||
const testSuiteId = process.argv[testSuiteArgIdx + 1];
|
||||
const testSuite = parsedSuitesFile.testSuites.find(suite => {
|
||||
return suite.id === testSuiteId;
|
||||
});
|
||||
|
||||
if (!testSuite) {
|
||||
console.error(`Test suite ${testSuiteId} is not defined`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (!testSuite.platforms.includes(platform)) {
|
||||
console.warn(
|
||||
`Test suite ${testSuiteId} is not enabled for your platform. Running it anyway.`
|
||||
);
|
||||
}
|
||||
|
||||
applicableSuites = [testSuite];
|
||||
}
|
||||
|
||||
return applicableSuites;
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const platform = zPlatform.parse(os.platform());
|
||||
|
||||
const expectations = readJSON(
|
||||
path.join(process.cwd(), 'test', 'TestExpectations.json')
|
||||
) as TestExpectation[];
|
||||
|
||||
const parsedSuitesFile = zTestSuiteFile.parse(
|
||||
readJSON(path.join(process.cwd(), 'test', 'TestSuites.json'))
|
||||
);
|
||||
|
||||
const applicableSuites = getApplicableTestSuites(parsedSuitesFile, platform);
|
||||
|
||||
console.log('Planning to run the following test suites', applicableSuites);
|
||||
|
||||
let fail = false;
|
||||
const recommendations = [];
|
||||
try {
|
||||
for (const suite of applicableSuites) {
|
||||
const parameters = suite.parameters;
|
||||
|
||||
const applicableExpectations = filterByParameters(
|
||||
filterByPlatform(expectations, platform),
|
||||
parameters
|
||||
);
|
||||
|
||||
const skippedTests = getSkippedTests(applicableExpectations);
|
||||
|
||||
const env = extendProcessEnv([
|
||||
...parameters.map(param => {
|
||||
return parsedSuitesFile.parameterDefinitons[param];
|
||||
}),
|
||||
{
|
||||
PUPPETEER_SKIPPED_TEST_CONFIG: JSON.stringify(
|
||||
skippedTests.map(ex => {
|
||||
return ex.testIdPattern;
|
||||
})
|
||||
),
|
||||
},
|
||||
]);
|
||||
|
||||
const tmpDir = fs.mkdtempSync(
|
||||
path.join(os.tmpdir(), 'puppeteer-test-runner-')
|
||||
);
|
||||
const tmpFilename = path.join(tmpDir, 'output.json');
|
||||
console.log('Running', JSON.stringify(parameters), tmpFilename);
|
||||
const handle = spawn(
|
||||
'npx mocha',
|
||||
['--reporter=json', '--reporter-option', 'output=' + tmpFilename],
|
||||
{
|
||||
shell: true,
|
||||
cwd: process.cwd(),
|
||||
stdio: 'inherit',
|
||||
env,
|
||||
}
|
||||
);
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
handle.on('error', err => {
|
||||
reject(err);
|
||||
});
|
||||
handle.on('close', () => {
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
console.log('Finished', JSON.stringify(parameters));
|
||||
try {
|
||||
const results = readJSON(tmpFilename) as MochaResults;
|
||||
console.log('Results from mocha');
|
||||
console.log('Stats', JSON.stringify(results.stats));
|
||||
results.pending.length > 0 && console.log('# Pending tests');
|
||||
for (const test of results.pending) {
|
||||
console.log(`\t? ${test.fullTitle} ${test.file}`);
|
||||
}
|
||||
results.failures.length > 0 && console.log('# Failed tests');
|
||||
for (const test of results.failures) {
|
||||
console.log(`\tF ${test.fullTitle} ${test.file}`, test.err);
|
||||
}
|
||||
const recommendation = getExpectationUpdates(
|
||||
results,
|
||||
applicableExpectations,
|
||||
{
|
||||
platforms: [os.platform()],
|
||||
parameters,
|
||||
}
|
||||
);
|
||||
if (recommendation.length > 0) {
|
||||
fail = true;
|
||||
recommendations.push(...recommendation);
|
||||
} else {
|
||||
console.log('Test run matches expecations');
|
||||
continue;
|
||||
}
|
||||
} catch (err) {
|
||||
fail = true;
|
||||
console.error(err);
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
fail = true;
|
||||
console.error(err);
|
||||
} finally {
|
||||
const toAdd = recommendations.filter(item => {
|
||||
return item.action === 'add';
|
||||
});
|
||||
if (toAdd.length) {
|
||||
console.log(
|
||||
'Add the following to TestExpecations.json to ignore the error:'
|
||||
);
|
||||
prettyPrintJSON(
|
||||
toAdd.map(item => {
|
||||
return item.expectation;
|
||||
})
|
||||
);
|
||||
}
|
||||
const toRemove = recommendations.filter(item => {
|
||||
return item.action === 'remove';
|
||||
});
|
||||
if (toRemove.length) {
|
||||
console.log(
|
||||
'Remove the following from the TestExpecations.json to ignore the error:'
|
||||
);
|
||||
prettyPrintJSON(
|
||||
toRemove.map(item => {
|
||||
return item.expectation;
|
||||
})
|
||||
);
|
||||
}
|
||||
const toUpdate = recommendations.filter(item => {
|
||||
return item.action === 'update';
|
||||
});
|
||||
if (toUpdate.length) {
|
||||
console.log(
|
||||
'Update the following expectations in the TestExpecations.json to ignore the error:'
|
||||
);
|
||||
prettyPrintJSON(
|
||||
toUpdate.map(item => {
|
||||
return item.expectation;
|
||||
})
|
||||
);
|
||||
}
|
||||
process.exit(fail ? 1 : 0);
|
||||
}
|
||||
}
|
||||
|
||||
main().catch(error => {
|
||||
console.error(error);
|
||||
process.exit(1);
|
||||
});
|
46
utils/mochaRunner/src/test.ts
Normal file
46
utils/mochaRunner/src/test.ts
Normal file
@ -0,0 +1,46 @@
|
||||
import assert from 'assert/strict';
|
||||
import test from 'node:test';
|
||||
import {filterByParameters, getTestResultForFailure} from './utils.js';
|
||||
import {TestExpectation} from './types.js';
|
||||
import {getFilename, extendProcessEnv} from './utils.js';
|
||||
|
||||
test('extendProcessEnv', () => {
|
||||
const env = extendProcessEnv([{TEST: 'TEST'}, {TEST2: 'TEST2'}]);
|
||||
assert.equal(env['TEST'], 'TEST');
|
||||
assert.equal(env['TEST2'], 'TEST2');
|
||||
});
|
||||
|
||||
test('getFilename', () => {
|
||||
assert.equal(getFilename('/etc/test.ts'), 'test');
|
||||
assert.equal(getFilename('/etc/test.js'), 'test');
|
||||
});
|
||||
|
||||
test('getTestResultForFailure', () => {
|
||||
assert.equal(
|
||||
getTestResultForFailure({err: {code: 'ERR_MOCHA_TIMEOUT'}}),
|
||||
'TIMEOUT'
|
||||
);
|
||||
assert.equal(getTestResultForFailure({err: {code: 'ERROR'}}), 'FAIL');
|
||||
});
|
||||
|
||||
test('filterByParameters', () => {
|
||||
const expectations: TestExpectation[] = [
|
||||
{
|
||||
testIdPattern:
|
||||
'[oopif.spec] OOPIF "after all" hook for "should keep track of a frames OOP state"',
|
||||
platforms: ['darwin'],
|
||||
parameters: ['firefox', 'headless'],
|
||||
expectations: ['FAIL'],
|
||||
},
|
||||
];
|
||||
assert.equal(
|
||||
filterByParameters(expectations, ['firefox', 'headless']).length,
|
||||
1
|
||||
);
|
||||
assert.equal(filterByParameters(expectations, ['firefox']).length, 0);
|
||||
assert.equal(
|
||||
filterByParameters(expectations, ['firefox', 'headless', 'other']).length,
|
||||
1
|
||||
);
|
||||
assert.equal(filterByParameters(expectations, ['other']).length, 0);
|
||||
});
|
42
utils/mochaRunner/src/types.ts
Normal file
42
utils/mochaRunner/src/types.ts
Normal file
@ -0,0 +1,42 @@
|
||||
import {z} from 'zod';
|
||||
|
||||
export const zPlatform = z.enum(['win32', 'linux', 'darwin']);
|
||||
|
||||
export type Platform = z.infer<typeof zPlatform>;
|
||||
|
||||
export const zTestSuite = z.object({
|
||||
id: z.string(),
|
||||
platforms: z.array(zPlatform),
|
||||
parameters: z.array(z.string()),
|
||||
});
|
||||
|
||||
export type TestSuite = z.infer<typeof zTestSuite>;
|
||||
|
||||
export const zTestSuiteFile = z.object({
|
||||
testSuites: z.array(zTestSuite),
|
||||
parameterDefinitons: z.record(z.any()),
|
||||
});
|
||||
|
||||
export type TestSuiteFile = z.infer<typeof zTestSuiteFile>;
|
||||
|
||||
export type TestResult = 'PASS' | 'FAIL' | 'TIMEOUT' | 'SKIP';
|
||||
|
||||
export type TestExpectation = {
|
||||
testIdPattern: string;
|
||||
platforms: NodeJS.Platform[];
|
||||
parameters: string[];
|
||||
expectations: TestResult[];
|
||||
};
|
||||
|
||||
export type MochaTestResult = {
|
||||
fullTitle: string;
|
||||
file: string;
|
||||
err?: {code: string};
|
||||
};
|
||||
|
||||
export type MochaResults = {
|
||||
stats: unknown;
|
||||
pending: MochaTestResult[];
|
||||
passes: MochaTestResult[];
|
||||
failures: MochaTestResult[];
|
||||
};
|
153
utils/mochaRunner/src/utils.ts
Normal file
153
utils/mochaRunner/src/utils.ts
Normal file
@ -0,0 +1,153 @@
|
||||
import {
|
||||
MochaTestResult,
|
||||
TestExpectation,
|
||||
MochaResults,
|
||||
TestResult,
|
||||
} from './types.js';
|
||||
import path from 'path';
|
||||
import fs from 'fs';
|
||||
|
||||
export function extendProcessEnv(envs: object[]): NodeJS.ProcessEnv {
|
||||
return envs.reduce(
|
||||
(acc: object, item: object) => {
|
||||
Object.assign(acc, item);
|
||||
return acc;
|
||||
},
|
||||
{
|
||||
...process.env,
|
||||
}
|
||||
) as NodeJS.ProcessEnv;
|
||||
}
|
||||
|
||||
export function getFilename(file: string): string {
|
||||
return path.basename(file).replace(path.extname(file), '');
|
||||
}
|
||||
|
||||
export function readJSON(path: string): unknown {
|
||||
return JSON.parse(fs.readFileSync(path, 'utf-8'));
|
||||
}
|
||||
|
||||
export function filterByPlatform<T extends {platforms: NodeJS.Platform[]}>(
|
||||
items: T[],
|
||||
platform: NodeJS.Platform
|
||||
): T[] {
|
||||
return items.filter(item => {
|
||||
return item.platforms.includes(platform);
|
||||
});
|
||||
}
|
||||
|
||||
export function prettyPrintJSON(json: unknown): void {
|
||||
console.log(JSON.stringify(json, null, 2));
|
||||
}
|
||||
|
||||
export function filterByParameters(
|
||||
expecations: TestExpectation[],
|
||||
parameters: string[]
|
||||
): TestExpectation[] {
|
||||
const querySet = new Set(parameters);
|
||||
return expecations.filter(ex => {
|
||||
return ex.parameters.every(param => {
|
||||
return querySet.has(param);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* The last expectation that matches the startsWith filter wins.
|
||||
*/
|
||||
export function findEffectiveExpecationForTest(
|
||||
expectations: TestExpectation[],
|
||||
result: MochaTestResult
|
||||
): TestExpectation | undefined {
|
||||
return expectations
|
||||
.filter(expecation => {
|
||||
if (
|
||||
getTestId(result.file, result.fullTitle).startsWith(
|
||||
expecation.testIdPattern
|
||||
)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
})
|
||||
.pop();
|
||||
}
|
||||
|
||||
type RecommendedExpecation = {
|
||||
expectation: TestExpectation;
|
||||
test: MochaTestResult;
|
||||
action: 'remove' | 'add' | 'update';
|
||||
};
|
||||
|
||||
export function getExpectationUpdates(
|
||||
results: MochaResults,
|
||||
expecations: TestExpectation[],
|
||||
context: {
|
||||
platforms: NodeJS.Platform[];
|
||||
parameters: string[];
|
||||
}
|
||||
): RecommendedExpecation[] {
|
||||
const output: RecommendedExpecation[] = [];
|
||||
|
||||
for (const pass of results.passes) {
|
||||
const expectation = findEffectiveExpecationForTest(expecations, pass);
|
||||
if (expectation && !expectation.expectations.includes('PASS')) {
|
||||
output.push({
|
||||
expectation,
|
||||
test: pass,
|
||||
action: 'remove',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
for (const failure of results.failures) {
|
||||
const expectation = findEffectiveExpecationForTest(expecations, failure);
|
||||
if (expectation) {
|
||||
if (
|
||||
!expectation.expectations.includes(getTestResultForFailure(failure))
|
||||
) {
|
||||
output.push({
|
||||
expectation: {
|
||||
...expectation,
|
||||
expectations: [
|
||||
...expectation.expectations,
|
||||
getTestResultForFailure(failure),
|
||||
],
|
||||
},
|
||||
test: failure,
|
||||
action: 'update',
|
||||
});
|
||||
}
|
||||
} else {
|
||||
output.push({
|
||||
expectation: {
|
||||
testIdPattern: getTestId(failure.file, failure.fullTitle),
|
||||
platforms: context.platforms,
|
||||
parameters: context.parameters,
|
||||
expectations: [getTestResultForFailure(failure)],
|
||||
},
|
||||
test: failure,
|
||||
action: 'add',
|
||||
});
|
||||
}
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
export function getTestResultForFailure(
|
||||
test: Pick<MochaTestResult, 'err'>
|
||||
): TestResult {
|
||||
return test.err?.code === 'ERR_MOCHA_TIMEOUT' ? 'TIMEOUT' : 'FAIL';
|
||||
}
|
||||
|
||||
export function getSkippedTests(
|
||||
expectations: TestExpectation[]
|
||||
): TestExpectation[] {
|
||||
return expectations.filter(ex => {
|
||||
return ex.expectations.includes('SKIP');
|
||||
});
|
||||
}
|
||||
|
||||
export function getTestId(file: string, fullTitle: string): string {
|
||||
return `[${getFilename(file)}] ${fullTitle}`;
|
||||
}
|
11
utils/mochaRunner/tsconfig.json
Normal file
11
utils/mochaRunner/tsconfig.json
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"allowJs": true,
|
||||
"composite": true,
|
||||
"module": "CommonJS",
|
||||
"outDir": "lib",
|
||||
"rootDir": "src"
|
||||
},
|
||||
"include": ["src"]
|
||||
}
|
Loading…
Reference in New Issue
Block a user