This Pr largely tightens up a lot of the code. 'v8' is no longer imported
outside of js. A number of helper functions have been moved to the js.Context.
For example, js.Function.getName used to call:
```zig
return js.valueToString(allocator, name, self.context.isolate, self.context.v8_context);
```
It now calls:
```zig
return self.context.valueToString(name, .{ .allocator = allocator });
```
Page.main_context has been renamed to `Page.js`. This, in combination with new
promise helpers, turns:
```zig
const resolver = page.main_context.createPromiseResolver();
try resolver.resolve({});
return resolver.promise();
```
into:
```zig
return page.js.resolvePromise({});
```
Back in the zig-js-runtime days, globals were used for the state and webapi
declarations. This caused problems largely because it was done across
compilation units (using @import("root")...).
The generic Env(S, WebApi) was used to solve these problems, while still making
it work for different States and WebApis.
This change removes the generics and hard-codes the *Page as the state and
only supports our WebApis for the class declarations.
To accommodate this change, the runtime/*tests* have been removed. I don't
consider this a huge loss - whatever behavior these were testing, already
exists in the browser/**/*.zig web api.
As we write more complex/complete WebApis, we're seeing more and more cases
that need to rely on js objects directly (JsObject, Function, Promises, etc...).
The goal is to make these easier to use. Rather than using Env.JsObject, you
now import "js.zig" and use js.JsObject (TODO: rename JsObject to Object).
Everything is just a plain Zig struct, rather than being nested in a generic.
After this change, I plan on:
1 - Renaming the js objects, JsObject -> Object. These should be referenced in
the webapi as js.Object, js.This, ...
2 - Splitting the code across multiple files (Env.zig, Context.zig,
Caller.zig, ...)
There is some risk to this change. The first is that I made a mistake. The
other is that one of the APIs that doesn't currently return an error changes
in the future.
Further reducing bouncing between page and server for loop polling. If there is
a page, the page polls. If there isn't a page, the server polls. Simpler.
Fix events.get_timeStamp (was events.get_timestamp, wrong casing).
Rename `newRunner` to `htmlRunner`.
move tests to src/tests (from src/browser/tests). src/runtime and possibly other
parts might want to have html tests too.
Follows up on https://github.com/lightpanda-io/browser/pull/994 and replaces
the jsRunner with a new page.navigation-based test runner.
Currently only implemented for the Window tests, looking for feedback and
converting every existing test will take time - so for a while, newRunner (to be
renamed) will sit side-by-side with jsRunner.
In addition to the benefits outlined in 994, largely around code simplicity and
putting more of the actual code under tests, I think our WebAPI tests
particularly benefit from:
1 - No need to recompile when modifying the html tests
2 - Much better assertions, e.g. you can assert that something is actually an
array, not just a string representation of an array
3 - Ability to test some edge cases (e.g. dynamic script loading)
I've put some effort into testing.js to make sure that, if the encapsulating
zig test passes, it's because it actually passed, not because it didn't run.
For the time being, console tests are removed. I think it's more useful to have
access to the console within tests, than it is to test the console (which is
just a wrapper around log, which is both tested and heavily used).
The thin mimalloc API is currently defensive around incorrect setup/teardown by
guarding against using/destroying the arena when the heap is null, or creating
an arena when it already exists.
The only time these checks will fail is when the code is wrong, e.g. trying
to use libdom before or after freeing the arena. The current behavior can mask
these errors, plus add runtime overhead.
Removes optional platform, which only existed for tests.
There is now a global `@import("testing.zig").test_app` available. This is setup
when the test runner starts, and cleaned up at the end of tests. Individual
tests don't have to worry about creating app, which I assume was the reason I
Platform optional, since that woul dhave been something else that needed to be
setup.
Allow page.wait to transition page mode.
Optimize initial page load. No point running scheduler until the initial
page is loaded.
Support ISO-8859-1 charset
This is hacky, but it's inspired by how NetSurf does it. While the Window isn't
the parent of the Document, many events should bubble from the Document to the
Window. libdom simply doesn't handle this (it has no concept of a Window, and
the Document has no parent).
We potentially need to do this for multiple event types (NetSurf only does it
for the 'load' event as far as I can tell). It would be nice to find a generic
way to do this...maybe intercept any addEventListener on the body and
registering special events on the Window? For now, `DOMContentLoaded` is the
blocking (for finance.yahoo.com) and we can see if this is really an issue for
other event types.
- Add 2 internal notifications
1 - http_request_start
2 - http_request_complete
- When Network.enable CDP message is received, browser context registers for
these 2 events (when Network.disable is called, it unregisters)
- On http_request_start, CDP will emit a Network.requestWillBeSent message.
This _does not_ include all the fields, but what we have appears to be enough
for puppeteer.waitForNetworkIdle.
- On http_request_complete, CDP will emit a Network.responseReceived message.
This _does not_ include all the fields, bu what we have appears to be enough
for puppeteer.waitForNetworkIdle.
We currently don't emit any other new events, including any network-specific
lifecycleEvent (i.e. Chrome will emit an networkIdle and networkAlmostIdle).
To support this, the following other things were done:
- CDP now has a `notification_arena` which is re-used between browser contexts.
Normally, CDP code runs based on a "cmd" which has its own message_arena, but
these notifications happen out-of-band, so we needed a new arena which is
valid for handling 1 notification.
- HTTP Client is notification-aware. The SessionState no longer includes the
*http.Client directly. It instead includes an http.RequestFactory which is
the combination fo the client + a specific configuration (i.e. *Notification).
This ensures that all requests made from that factory have the same settings.
- However, despite the above, _some_ requests do not appear to emit CDP events,
such as loading a <script src="X">. So the page still deals directly with the
*http.Client.
- Playwright and Puppeteer (but Playwright in particular) are very sensitive to
event ordering. These new events have introduced additional sensitivity.
The result sent to Page.navigate had to be moved to inside the navigate event
handler, which meant passing some cdp-specific data (the input.id) into the
NavigateOpts. This is the only way I found to keep both happy - the sequence
of events is closer (but still pretty far) from what Chrome does.
- Pages within the same session have proper isolation
- they have their own window
- they have their own SessionState
- they have their own v8.Context
- Move inspector to CDP browser context
- Browser now knows nothing about the inspector
- Use notification to emit a context-created message
- This is still a bit hacky, but again, it decouples browser from CDP
Synchronous body reader now exposes a peek() function to get the first few bytes
from the response body. This will be no less than 100 bytes (assuming the body
is that big), but could be more. Streaming API, via res.next() continues to work
as-is even if peek() is called.
Introduce Mime.sniff() that detects a few common types - the ones that we care
about right now - from the body content.
Having a js source name is useful to detect where the error comes from.
Using `null` generates messages with `<anonymous>` source name.
eg. `ReferenceError: report is not defined\n at <anonymous>:1:1`
vs. `ReferenceError: report is not defined\n at teststatus:1:1`
index_get seems to be ~1000x slower than setting the value directly on the
v8.Object. There's a lot of information on "v8 fast properties", and values
set directly on objects seem to be heavily optimized. Still, I can't imagine
indexed properties are always _that_ slow, so I must be doing something wrong.
Still, for now, this brings back the original functionality / behavior / perf.
Introduce the ability for Zig functions to take a Env.JsObject parameter. While
this isn't currently being used, it aligns with bringing back the postAttach /
JSObject functionality in main.
Moved function *State to the end of the function list (making it consistent with
getters and setters). The optional Env.JsObject parameter comes after the
optional state.
Removed some uncessary arena deinits from a few webapis.
Remove Env from caller, and don't store Env in isolate. We don't need it, we
can execute all runtime code from the Executor (which we store a pointer to
in the v8.Context)