chore: support typed arrays in indexeddb
This commit is contained in:
parent
837abfbc15
commit
1837b1bf4b
|
|
@ -1530,10 +1530,6 @@ Returns storage state for this browser context, contains current cookies, local
|
|||
Set to `true` to include IndexedDB in the storage state snapshot.
|
||||
If your application uses IndexedDB to store authentication tokens, like Firebase Authentication, enable this.
|
||||
|
||||
:::note
|
||||
IndexedDBs with typed arrays are currently not supported.
|
||||
:::
|
||||
|
||||
## property: BrowserContext.tracing
|
||||
* since: v1.12
|
||||
- type: <[Tracing]>
|
||||
|
|
|
|||
3
packages/playwright-client/types/types.d.ts
vendored
3
packages/playwright-client/types/types.d.ts
vendored
|
|
@ -9273,9 +9273,6 @@ export interface BrowserContext {
|
|||
/**
|
||||
* Set to `true` to include IndexedDB in the storage state snapshot. If your application uses IndexedDB to store
|
||||
* authentication tokens, like Firebase Authentication, enable this.
|
||||
*
|
||||
* **NOTE** IndexedDBs with typed arrays are currently not supported.
|
||||
*
|
||||
*/
|
||||
indexedDB?: boolean;
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,8 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
type TypedArrayKind = 'i8' | 'ui8' | 'ui8c' | 'i16' | 'ui16' | 'i32' | 'ui32' | 'f32' | 'f64' | 'bi64' | 'bui64';
|
||||
|
||||
export type SerializedValue =
|
||||
undefined | boolean | number | string |
|
||||
{ v: 'null' | 'undefined' | 'NaN' | 'Infinity' | '-Infinity' | '-0' } |
|
||||
|
|
@ -25,7 +27,8 @@ export type SerializedValue =
|
|||
{ a: SerializedValue[], id: number } |
|
||||
{ o: { k: string, v: SerializedValue }[], id: number } |
|
||||
{ ref: number } |
|
||||
{ h: number };
|
||||
{ h: number } |
|
||||
{ ta: { b: string, k: TypedArrayKind } };
|
||||
|
||||
export type HandleOrValue = { h: number } | { fallThrough: any };
|
||||
|
||||
|
|
@ -68,6 +71,42 @@ export function source() {
|
|||
}
|
||||
}
|
||||
|
||||
const typedArrayCtors: Record<TypedArrayKind, Function> = {
|
||||
i8: Int8Array,
|
||||
ui8: Uint8Array,
|
||||
ui8c: Uint8ClampedArray,
|
||||
i16: Int16Array,
|
||||
ui16: Uint16Array,
|
||||
i32: Int32Array,
|
||||
ui32: Uint32Array,
|
||||
// TODO: add Float16Array once it's in baseline
|
||||
f32: Float32Array,
|
||||
f64: Float64Array,
|
||||
bi64: BigInt64Array,
|
||||
bui64: BigUint64Array,
|
||||
};
|
||||
|
||||
function typedArrayToBase64(array: any) {
|
||||
if (globalThis.Buffer)
|
||||
return Buffer.from(array).toString('base64');
|
||||
|
||||
const binary = Array.from(new Uint8Array(array.buffer)).map(b => String.fromCharCode(b)).join('');
|
||||
return btoa(binary);
|
||||
}
|
||||
|
||||
function base64ToTypedArray(base64: string, TypedArrayConstructor: any) {
|
||||
if (globalThis.Buffer) {
|
||||
const buf = Buffer.from(base64, 'base64');
|
||||
return new TypedArrayConstructor(buf.buffer, buf.byteOffset, buf.byteLength / buf.BYTES_PER_ELEMENT);
|
||||
}
|
||||
|
||||
const binary = atob(base64);
|
||||
const bytes = new Uint8Array(binary.length);
|
||||
for (let i = 0; i < binary.length; i++)
|
||||
bytes[i] = binary.charCodeAt(i);
|
||||
return new TypedArrayConstructor(bytes.buffer);
|
||||
}
|
||||
|
||||
function parseEvaluationResultValue(value: SerializedValue, handles: any[] = [], refs: Map<number, object> = new Map()): any {
|
||||
if (Object.is(value, undefined))
|
||||
return undefined;
|
||||
|
|
@ -119,6 +158,8 @@ export function source() {
|
|||
}
|
||||
if ('h' in value)
|
||||
return handles[value.h];
|
||||
if ('ta' in value)
|
||||
return base64ToTypedArray(value.ta.b, typedArrayCtors[value.ta.k]);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
|
@ -186,6 +227,10 @@ export function source() {
|
|||
return { u: value.toJSON() };
|
||||
if (isRegExp(value))
|
||||
return { r: { p: value.source, f: value.flags } };
|
||||
for (const [k, ctor] of Object.entries(typedArrayCtors) as [TypedArrayKind, Function][]) {
|
||||
if (value instanceof ctor)
|
||||
return { ta: { b: typedArrayToBase64(value), k } };
|
||||
}
|
||||
|
||||
const id = visitorInfo.visited.get(value);
|
||||
if (id)
|
||||
|
|
|
|||
3
packages/playwright-core/types/types.d.ts
vendored
3
packages/playwright-core/types/types.d.ts
vendored
|
|
@ -9273,9 +9273,6 @@ export interface BrowserContext {
|
|||
/**
|
||||
* Set to `true` to include IndexedDB in the storage state snapshot. If your application uses IndexedDB to store
|
||||
* authentication tokens, like Firebase Authentication, enable this.
|
||||
*
|
||||
* **NOTE** IndexedDBs with typed arrays are currently not supported.
|
||||
*
|
||||
*/
|
||||
indexedDB?: boolean;
|
||||
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ it('should round-trip through the file', async ({ contextFactory }, testInfo) =>
|
|||
.put({ name: 'foo', date: new Date(0) });
|
||||
transaction
|
||||
.objectStore('store2')
|
||||
.put('bar', 'foo');
|
||||
.put(new TextEncoder().encode('bar'), 'foo');
|
||||
transaction.addEventListener('complete', resolve);
|
||||
transaction.addEventListener('error', reject);
|
||||
};
|
||||
|
|
@ -126,16 +126,18 @@ it('should round-trip through the file', async ({ contextFactory }, testInfo) =>
|
|||
expect(cookie).toEqual('username=John Doe');
|
||||
const idbValues = await page2.evaluate(() => new Promise((resolve, reject) => {
|
||||
const openRequest = indexedDB.open('db', 42);
|
||||
openRequest.addEventListener('success', () => {
|
||||
openRequest.addEventListener('success', async () => {
|
||||
const db = openRequest.result;
|
||||
const transaction = db.transaction(['store', 'store2'], 'readonly');
|
||||
const request1 = transaction.objectStore('store').get('foo');
|
||||
const request2 = transaction.objectStore('store2').get('foo');
|
||||
|
||||
Promise.all([request1, request2].map(request => new Promise((resolve, reject) => {
|
||||
const [result1, result2] = await Promise.all([request1, request2].map(request => new Promise((resolve, reject) => {
|
||||
request.addEventListener('success', () => resolve(request.result));
|
||||
request.addEventListener('error', () => reject(request.error));
|
||||
}))).then(resolve, reject);
|
||||
})));
|
||||
|
||||
resolve([result1, new TextDecoder().decode(result2 as any)]);
|
||||
});
|
||||
openRequest.addEventListener('error', () => reject(openRequest.error));
|
||||
}));
|
||||
|
|
|
|||
Loading…
Reference in a new issue