Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

create and navigate.browsingContext #55

Merged
merged 9 commits into from
Nov 2, 2021
43 changes: 33 additions & 10 deletions src/bidiMapper/bidiProtocolTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ export namespace Script {
// https://w3c.github.io/webdriver-bidi/#module-browsingContext
export namespace BrowsingContext {
export type BrowsingContext = string;
export type Navigation = string;

export type BrowsingContextGetTreeCommand = {
method: 'browsingContext.getTree';
Expand All @@ -119,20 +120,42 @@ export namespace BrowsingContext {
children: BrowsingContextInfoList;
};

// `browsingContext.create`
export type BrowsingContextCreateCommand = {
method: 'browsingContext.create';
params: BrowsingContextCreateParameters;
export type BrowsingContextNavigateCommand = {
method: 'browsingContext.navigate';
params: BrowsingContextNavigateParameters;
};

export type BrowsingContextCreateType = 'tab' | 'window';

export type BrowsingContextCreateParameters = {
type: BrowsingContextCreateType;
};
export type BrowsingContextCreateResult = {
export type BrowsingContextNavigateParameters = {
context: BrowsingContext;
url: string;
wait?: ReadinessState;
};

export type ReadinessState = 'none';
// TODO sadym: implement 'interactive' and 'complete' states.
export type BrowsingContextNavigateResult = {
navigation?: Navigation;
url: string;
};

export namespace PROTO {
// `browsingContext.create`:
// https://github.com/w3c/webdriver-bidi/pull/133
export type BrowsingContextCreateCommand = {
method: 'PROTO.browsingContext.create';
params: BrowsingContextCreateParameters;
};

export type BrowsingContextCreateType = 'tab' | 'window';

export type BrowsingContextCreateParameters = {
type?: BrowsingContextCreateType;
};

export type BrowsingContextCreateResult = {
context: BrowsingContext;
};
}
}

export namespace Session {
Expand Down
32 changes: 15 additions & 17 deletions src/bidiMapper/commandProcessor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,14 @@ export class CommandProcessor {
static run(
cdpConnection: CdpConnection,
bidiServer: IBidiServer,
selfTargetId: string
selfTargetId: string,
EVALUATOR_SCRIPT: string
) {
const commandProcessor = new CommandProcessor(
cdpConnection,
bidiServer,
selfTargetId
selfTargetId,
EVALUATOR_SCRIPT
);

commandProcessor.run();
Expand All @@ -43,7 +45,8 @@ export class CommandProcessor {
private constructor(
private _cdpConnection: CdpConnection,
private _bidiServer: IBidiServer,
private _selfTargetId: string
private _selfTargetId: string,
EVALUATOR_SCRIPT: string
) {
this._browserCdpClient = this._cdpConnection.browserClient();

Expand All @@ -55,21 +58,12 @@ export class CommandProcessor {
},
(t: Context) => {
return this._onContextDestroyed(t);
}
},
EVALUATOR_SCRIPT
);
}

private run() {
this._browserCdpClient.Target.on('attachedToTarget', async (params) => {
await this._contextProcessor.handleAttachedToTargetEvent(params);
});
this._browserCdpClient.Target.on('targetInfoChanged', (params) => {
this._contextProcessor.handleInfoChangedEvent(params);
});
this._browserCdpClient.Target.on('detachedFromTarget', (params) => {
this._contextProcessor.handleDetachedFromTargetEvent(params);
});

this._bidiServer.on('message', (messageObj) => {
return this._onBidiMessage(messageObj);
});
Expand Down Expand Up @@ -181,9 +175,13 @@ export class CommandProcessor {
return await this._contextProcessor.process_script_evaluate(
commandData as Script.ScriptEvaluateCommand
);
case 'browsingContext.create':
return await this._contextProcessor.process_createContext(
commandData as BrowsingContext.BrowsingContextCreateCommand
case 'PROTO.browsingContext.create':
return await this._contextProcessor.process_PROTO_browsingContext_create(
commandData as BrowsingContext.PROTO.BrowsingContextCreateCommand
);
case 'browsingContext.navigate':
return await this._contextProcessor.process_browsingContext_navigate(
commandData as BrowsingContext.BrowsingContextNavigateCommand
);

case 'PROTO.script.invoke':
Expand Down
152 changes: 152 additions & 0 deletions src/bidiMapper/domains/context/browsingContextProcessor.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
/**
* Copyright 2021 Google LLC.
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { StubTransport } from '../../../tests/stubTransport.spec';

import * as chai from 'chai';
import chaiAsPromised from 'chai-as-promised';
chai.use(chaiAsPromised);

import * as sinon from 'sinon';

import { BrowsingContextProcessor } from './browsingContextProcessor';
import { CdpConnection, CdpClient } from '../../../cdp';
import { Context } from './context';
import { BrowsingContext } from '../../bidiProtocolTypes';

describe('BrowsingContextProcessor', function () {
let mockCdpServer: StubTransport;
let browsingContextProcessor: BrowsingContextProcessor;
let cdpConnection: CdpConnection;

const EVALUATOR_SCRIPT = 'EVALUATOR_SCRIPT';
const NEW_CONTEXT_ID = 'NEW_CONTEXT_ID';
const TARGET_ATTACHED_TO_TARGET_EVENT = {
method: 'Target.attachedToTarget',
params: {
sessionId: '_ANY_VALUE_',
targetInfo: {
targetId: NEW_CONTEXT_ID,
type: 'page',
title: '',
url: '',
attached: true,
canAccessOpener: false,
browserContextId: '_ANY_ANOTHER_VALUE_',
},
waitingForDebugger: false,
},
};

beforeEach(async function () {
mockCdpServer = new StubTransport();
cdpConnection = new CdpConnection(mockCdpServer);
browsingContextProcessor = new BrowsingContextProcessor(
cdpConnection,
'SELF_TARGET_ID',
sinon.fake(),
sinon.fake(),
EVALUATOR_SCRIPT
);

// Actual `Context.create` logic involves several CDP calls, so mock it to avoid all the simulations.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a helpful comment, thanks!

Context.create = sinon.fake(
async (_1: string, _2: CdpClient, _3: string) => {
return sinon.createStubInstance(Context) as unknown as Context;
}
);
});

describe('handle events', async function () {
it('`Target.attachedToTarget` creates Context', async function () {
sinon.assert.notCalled(Context.create as sinon.SinonSpy);
await mockCdpServer.emulateIncomingMessage(
TARGET_ATTACHED_TO_TARGET_EVENT
);
sinon.assert.calledOnceWithExactly(
Context.create as sinon.SinonSpy,
NEW_CONTEXT_ID,
sinon.match.any,
EVALUATOR_SCRIPT
);
});
});

describe('handle `process_PROTO_browsingContext_create`', async function () {
const BROWSING_CONTEXT_CREATE_COMMAND: BrowsingContext.PROTO.BrowsingContextCreateCommand =
{
method: 'PROTO.browsingContext.create',
params: {},
};

const EXPECTED_TARGET_CREATE_TARGET_CALL = {
id: 0,
method: 'Target.createTarget',
params: {
url: 'about:blank',
newWindow: false,
},
};

const TARGET_CREATE_TARGET_RESPONSE = {
id: 0,
result: {
targetId: NEW_CONTEXT_ID,
},
};

it('Target.attachedToTarget before command finished', async function () {
const createResultPromise =
browsingContextProcessor.process_PROTO_browsingContext_create(
BROWSING_CONTEXT_CREATE_COMMAND
);

sinon.assert.calledOnceWithExactly(
mockCdpServer.sendMessage,
JSON.stringify(EXPECTED_TARGET_CREATE_TARGET_CALL)
);

await mockCdpServer.emulateIncomingMessage(
TARGET_ATTACHED_TO_TARGET_EVENT
);

await mockCdpServer.emulateIncomingMessage(TARGET_CREATE_TARGET_RESPONSE);

await createResultPromise;
});

it('Target.attachedToTarget after command finished', async function () {
const createResultPromise =
browsingContextProcessor.process_PROTO_browsingContext_create(
BROWSING_CONTEXT_CREATE_COMMAND
);

sinon.assert.calledOnceWithExactly(
mockCdpServer.sendMessage,
JSON.stringify(EXPECTED_TARGET_CREATE_TARGET_CALL)
);

await mockCdpServer.emulateIncomingMessage(TARGET_CREATE_TARGET_RESPONSE);

await mockCdpServer.emulateIncomingMessage(
TARGET_ATTACHED_TO_TARGET_EVENT
);

await createResultPromise;
});
});
});
Loading