Skip to content

Commit

Permalink
chore: pass validator into validator context (#34810)
Browse files Browse the repository at this point in the history
  • Loading branch information
pavelfeldman authored Feb 15, 2025
1 parent 024a528 commit 3606a43
Show file tree
Hide file tree
Showing 6 changed files with 49 additions and 22 deletions.
10 changes: 9 additions & 1 deletion packages/playwright-core/src/client/channelOwner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,14 @@ export abstract class ChannelOwner<T extends channels.Channel = channels.Channel
};
}

private _validatorToWireContext(): ValidatorContext {
return {
tChannelImpl: tChannelImplToWire,
binary: this._connection.rawBuffers() ? 'buffer' : 'toBase64',
isUnderTest: () => this._platform.isUnderTest(),
};
}

private _createChannel(base: Object): T {
const channel = new Proxy(base, {
get: (obj: any, prop: string | symbol) => {
Expand All @@ -149,7 +157,7 @@ export abstract class ChannelOwner<T extends channels.Channel = channels.Channel
if (validator) {
return async (params: any) => {
return await this._wrapApiCall(async apiZone => {
const validatedParams = validator(params, '', { tChannelImpl: tChannelImplToWire, binary: this._connection.rawBuffers() ? 'buffer' : 'toBase64' });
const validatedParams = validator(params, '', this._validatorToWireContext());
if (!apiZone.isInternal && !apiZone.reported) {
// Reporting/tracing/logging this api call for the first time.
apiZone.params = params;
Expand Down
2 changes: 0 additions & 2 deletions packages/playwright-core/src/client/clientBundle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,10 @@

import { Connection } from './connection';
import { setPlatformForSelectors } from './selectors';
import { setIsUnderTestForValidator } from '../protocol/validatorPrimitives';

import type { Platform } from './platform';

export function createConnectionFactory(platform: Platform): () => Connection {
setPlatformForSelectors(platform);
setIsUnderTestForValidator(() => platform.isUnderTest());
return () => new Connection(platform);
}
14 changes: 11 additions & 3 deletions packages/playwright-core/src/client/connection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,14 @@ export class Connection extends EventEmitter {
return await new Promise((resolve, reject) => this._callbacks.set(id, { resolve, reject, apiName, type, method }));
}

private _validatorFromWireContext(): ValidatorContext {
return {
tChannelImpl: this._tChannelImplFromWire.bind(this),
binary: this._rawBuffers ? 'buffer' : 'fromBase64',
isUnderTest: () => this._platform.isUnderTest(),
};
}

dispatch(message: object) {
if (this._closedError)
return;
Expand All @@ -166,7 +174,7 @@ export class Connection extends EventEmitter {
callback.reject(parsedError);
} else {
const validator = findValidator(callback.type, callback.method, 'Result');
callback.resolve(validator(result, '', { tChannelImpl: this._tChannelImplFromWire.bind(this), binary: this._rawBuffers ? 'buffer' : 'fromBase64' }));
callback.resolve(validator(result, '', this._validatorFromWireContext()));
}
return;
}
Expand Down Expand Up @@ -196,7 +204,7 @@ export class Connection extends EventEmitter {
}

const validator = findValidator(object._type, method, 'Event');
(object._channel as any).emit(method, validator(params, '', { tChannelImpl: this._tChannelImplFromWire.bind(this), binary: this._rawBuffers ? 'buffer' : 'fromBase64' }));
(object._channel as any).emit(method, validator(params, '', this._validatorFromWireContext()));
}

close(cause?: string) {
Expand Down Expand Up @@ -227,7 +235,7 @@ export class Connection extends EventEmitter {
throw new Error(`Cannot find parent object ${parentGuid} to create ${guid}`);
let result: ChannelOwner<any>;
const validator = findValidator(type, '', 'Initializer');
initializer = validator(initializer, '', { tChannelImpl: this._tChannelImplFromWire.bind(this), binary: this._rawBuffers ? 'buffer' : 'fromBase64' });
initializer = validator(initializer, '', this._validatorFromWireContext());
switch (type) {
case 'Android':
result = new Android(parent, type, guid, initializer);
Expand Down
13 changes: 4 additions & 9 deletions packages/playwright-core/src/protocol/validatorPrimitives.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,12 @@
* limitations under the License.
*/

let isUnderTest = () => false;

export function setIsUnderTestForValidator(getter: () => boolean) {
isUnderTest = getter;
}

export class ValidationError extends Error {}
export type Validator = (arg: any, path: string, context: ValidatorContext) => any;
export type ValidatorContext = {
tChannelImpl: (names: '*' | string[], arg: any, path: string, context: ValidatorContext) => any,
binary: 'toBase64' | 'fromBase64' | 'buffer',
tChannelImpl: (names: '*' | string[], arg: any, path: string, context: ValidatorContext) => any;
binary: 'toBase64' | 'fromBase64' | 'buffer';
isUnderTest: () => boolean;
};
export const scheme: { [key: string]: Validator } = {};

Expand Down Expand Up @@ -117,7 +112,7 @@ export const tObject = (s: { [key: string]: Validator }): Validator => {
if (!Object.is(value, undefined))
result[key] = value;
}
if (isUnderTest()) {
if (context.isUnderTest()) {
for (const [key, value] of Object.entries(arg)) {
if (key.startsWith('__testHook'))
result[key] = value;
Expand Down
27 changes: 22 additions & 5 deletions packages/playwright-core/src/server/dispatchers/dispatcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -200,13 +200,13 @@ export class DispatcherConnection {

sendEvent(dispatcher: DispatcherScope, event: string, params: any) {
const validator = findValidator(dispatcher._type, event, 'Event');
params = validator(params, '', { tChannelImpl: this._tChannelImplToWire.bind(this), binary: this._isLocal ? 'buffer' : 'toBase64' });
params = validator(params, '', this._validatorToWireContext());
this.onmessage({ guid: dispatcher._guid, method: event, params });
}

sendCreate(parent: DispatcherScope, type: string, guid: string, initializer: any) {
const validator = findValidator(type, '', 'Initializer');
initializer = validator(initializer, '', { tChannelImpl: this._tChannelImplToWire.bind(this), binary: this._isLocal ? 'buffer' : 'toBase64' });
initializer = validator(initializer, '', this._validatorToWireContext());
this.onmessage({ guid: parent._guid, method: '__create__', params: { type, initializer, guid } });
}

Expand All @@ -218,6 +218,22 @@ export class DispatcherConnection {
this.onmessage({ guid: dispatcher._guid, method: '__dispose__', params: { reason } });
}

private _validatorToWireContext(): ValidatorContext {
return {
tChannelImpl: this._tChannelImplToWire.bind(this),
binary: this._isLocal ? 'buffer' : 'toBase64',
isUnderTest,
};
}

private _validatorFromWireContext(): ValidatorContext {
return {
tChannelImpl: this._tChannelImplFromWire.bind(this),
binary: this._isLocal ? 'buffer' : 'fromBase64',
isUnderTest,
};
}

private _tChannelImplFromWire(names: '*' | string[], arg: any, path: string, context: ValidatorContext): any {
if (arg && typeof arg === 'object' && typeof arg.guid === 'string') {
const guid = arg.guid;
Expand Down Expand Up @@ -279,8 +295,9 @@ export class DispatcherConnection {
let validMetadata: channels.Metadata;
try {
const validator = findValidator(dispatcher._type, method, 'Params');
validParams = validator(params, '', { tChannelImpl: this._tChannelImplFromWire.bind(this), binary: this._isLocal ? 'buffer' : 'fromBase64' });
validMetadata = metadataValidator(metadata, '', { tChannelImpl: this._tChannelImplFromWire.bind(this), binary: this._isLocal ? 'buffer' : 'fromBase64' });
const validatorContext = this._validatorFromWireContext();
validParams = validator(params, '', validatorContext);
validMetadata = metadataValidator(metadata, '', validatorContext);
if (typeof (dispatcher as any)[method] !== 'function')
throw new Error(`Mismatching dispatcher: "${dispatcher._type}" does not implement "${method}"`);
} catch (e) {
Expand Down Expand Up @@ -338,7 +355,7 @@ export class DispatcherConnection {
try {
const result = await dispatcher._handleCommand(callMetadata, method, validParams);
const validator = findValidator(dispatcher._type, method, 'Result');
response.result = validator(result, '', { tChannelImpl: this._tChannelImplToWire.bind(this), binary: this._isLocal ? 'buffer' : 'toBase64' });
response.result = validator(result, '', this._validatorToWireContext());
callMetadata.result = result;
} catch (e) {
if (isTargetClosedError(e) && sdkObject) {
Expand Down
5 changes: 3 additions & 2 deletions packages/playwright-core/src/server/socksInterceptor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import EventEmitter from 'events';

import * as socks from './utils/socksProxy';
import { ValidationError, findValidator } from '../protocol/validator';
import { isUnderTest } from './utils/debug';

import type { WebSocketTransport } from './transport';
import type { ValidatorContext } from '../protocol/validator';
Expand All @@ -42,7 +43,7 @@ export class SocksInterceptor {
const id = --lastId;
this._ids.add(id);
const validator = findValidator('SocksSupport', prop, 'Params');
params = validator(params, '', { tChannelImpl: tChannelForSocks, binary: 'toBase64' });
params = validator(params, '', { tChannelImpl: tChannelForSocks, binary: 'toBase64', isUnderTest });
transport.send({ id, guid: this._socksSupportObjectGuid, method: prop, params, metadata: { stack: [], apiName: '', internal: true } } as any);
} catch (e) {
}
Expand Down Expand Up @@ -74,7 +75,7 @@ export class SocksInterceptor {
}
if (this._socksSupportObjectGuid && message.guid === this._socksSupportObjectGuid) {
const validator = findValidator('SocksSupport', message.method, 'Event');
const params = validator(message.params, '', { tChannelImpl: tChannelForSocks, binary: 'fromBase64' });
const params = validator(message.params, '', { tChannelImpl: tChannelForSocks, binary: 'fromBase64', isUnderTest });
this._channel.emit(message.method, params);
return true;
}
Expand Down

0 comments on commit 3606a43

Please sign in to comment.