We should not stall selector actions because of dialogs
and properly timeout instead. For this, we should not await
the handle.dispose() call because it will never happen
while dialog is shown.
Also, log information about dialogs to make it easier to debug.
We now commit protocol.ts files during the roll.
New utils/roll_browser.js helps with that.
This makes our installation very shallow:
- build installer;
- download browsers.
Firefox and WebKit require native promises to provide awaitPromise
functionality. When the Promise is overwritten, all evaluations
in the main world produce wrong Promise, so we wrap with async
function to get a native promise instead.
We now query selector and take textContent synchronously. This
avoids any issues with async processing: node being recycled,
detached, etc.
More methods will follow with the same atomic pattern.
Drive-by: fixed selector engine names being sometimes case-sensitive
and sometimes not.
We currently return undefined whenever we had an error trying
return the evaluation result by error. The most common error
is "execution context destroyed".
This produces very unexpected undefined from methods that do not
ever expect undefined. Instead, we should throw because we were
not able to return the result.
We currently have dispatchEventTask and waitForSelectorTask.
However, most selector-based operations make sense as tasks, to ensure
atomic execution, e.g. textContent(selector) or focus(selector).
This will fight hydration, elements recycling and other async issues.
In preparation, decouple tasks from selectors parsing so that
we can have common infrastructure for tasks.
- Gave all possible dom errors distinct names, and throw them on the node side.
- Separated errors into FatalDOMError and RetargetableDOMError.
Fatal errors are unrecoverable. Retargetable errors
could be resolved by requerying the selector.
- This exposed a number of unhandled 'notconnected' cases.
- Added helper functions to handle errors and ensure TypeScript catches
unhandled ones.
Element screenshot now waits for the element to become visible and
throws on detach.
Both screenshot methods accept a timeout and capture logs using Progress.
Also, carefully handling exceptions and restoring the viewport.
WebKit and Firefox are only able to continue redirects.
Firefox is faking it on the backend, so you can't even stall it.
Instead, we just do not fire routes for redirects on all browsers,
to avoid surprises.
In addition to `PLAYWRIGHT_DOWNLOAD_HOST` env variable, this patch adds a per-browser
configuration:
- `PLAYWRIGHT_CHROMIUM_DOWNLOAD_HOST`
- `PLAYWRIGHT_FIREFOX_DOWNLOAD_HOST`
- `PLAYWRIGHT_WEBKIT_DOWNLOAD_HOST`
This reverts 2 commits:
- "fix(installer): create tmp directory inside `browserPath` (#2498)"
commit 946b4efa3b.
- "feat: support atomic installation of browsers (#2489)"
commit 3de0c087bc.
This addresses installation issues we see in some CI environments.
Currently, we fail when the predicate throws on the first call,
and timeout when it fails on any other call.
There are two possible ways to handle throwing predicates:
- Fail waitForFunction if predicate throws once. This is good
since it gives you the error faster.
- Tolerate predicate exceptions. This is good because you do
not have to worry about non-initialized state during load.
This change implements the former.
Currently, Ctrl-C while extracting browser might yield users in
a bad place.
This patch extracts browsers in a temp directory that is later
moved to a installer registry.
During remote -> local transition, these two events come in unpredictable order, so we try to handle both cases. Also, remote frame detach was not handled at all.
- unifies polling timeouts with everything else,
based on the client time instead of the server time;
- prepares polling tasks for cancellation token
behavior.
Unfortunately, RerunnableTask had to be rewritten almost
entirely.
We already skip <script> and <style> tags because they are not
the page content. Similar reasoning applies to <head> that has
content that is never rendered on the page.
A progress roughly corresponds to an api call. It is used:
- to collect logs related to the call;
- to handle timeout;
- to provide "cancellation token" behavior so that cancelable process can either
early-exit with progress.throwIfCanceled() or race against it with progress.race();
- to ensure resources are disposed in the case of a failure
with progress.cleanupWhenCanceled();
- (possibly) to log api calls if needed;
- (in the future) to augment async stacks.