Skip to content

Commit 81bb019

Browse files
author
Tim Wang
committed
address comments and add e2e tests
1 parent f984604 commit 81bb019

File tree

3 files changed

+112
-27
lines changed

3 files changed

+112
-27
lines changed

src/driver.ts

Lines changed: 33 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -36,25 +36,22 @@ import { iosPortForward, iosRemovePortForward } from './iOS';
3636
import type { PortForwardCallback, PortReleaseCallback } from './types';
3737
import _ from 'lodash';
3838

39-
import type {
40-
RouteMatcher
41-
} from '@appium/types';
39+
import type { RouteMatcher } from '@appium/types';
4240

4341
const WEBVIEW_NO_PROXY = [
44-
[`GET`, new RegExp(`^/session/[^/]+/appium`)],
45-
[`GET`, new RegExp(`^/session/[^/]+/context`)],
46-
[`GET`, new RegExp(`^/session/[^/]+/element/[^/]+/rect`)],
47-
[`GET`, new RegExp(`^/session/[^/]+/log/types$`)],
48-
[`GET`, new RegExp(`^/session/[^/]+/orientation`)],
49-
[`POST`, new RegExp(`^/session/[^/]+/appium`)],
50-
[`POST`, new RegExp(`^/session/[^/]+/context`)],
51-
[`POST`, new RegExp(`^/session/[^/]+/log$`)],
52-
[`POST`, new RegExp(`^/session/[^/]+/orientation`)],
53-
[`POST`, new RegExp(`^/session/[^/]+/touch/multi/perform`)],
54-
[`POST`, new RegExp(`^/session/[^/]+/touch/perform`)],
42+
[`GET`, new RegExp(`^/session/[^/]+/appium`)],
43+
[`GET`, new RegExp(`^/session/[^/]+/context`)],
44+
[`GET`, new RegExp(`^/session/[^/]+/element/[^/]+/rect`)],
45+
[`GET`, new RegExp(`^/session/[^/]+/log/types$`)],
46+
[`GET`, new RegExp(`^/session/[^/]+/orientation`)],
47+
[`POST`, new RegExp(`^/session/[^/]+/appium`)],
48+
[`POST`, new RegExp(`^/session/[^/]+/context`)],
49+
[`POST`, new RegExp(`^/session/[^/]+/log$`)],
50+
[`POST`, new RegExp(`^/session/[^/]+/orientation`)],
51+
[`POST`, new RegExp(`^/session/[^/]+/touch/multi/perform`)],
52+
[`POST`, new RegExp(`^/session/[^/]+/touch/perform`)],
5553
] as import('@appium/types').RouteMatcher[];
5654

57-
5855
export class AppiumFlutterDriver extends BaseDriver<FlutterDriverConstraints> {
5956
// @ts-ignore
6057
public proxydriver: XCUITestDriver | AndroidUiautomator2Driver;
@@ -215,19 +212,32 @@ export class AppiumFlutterDriver extends BaseDriver<FlutterDriverConstraints> {
215212
}
216213

217214
async executeCommand(command: any, ...args: any) {
218-
if (this.currentContext === this.NATIVE_CONTEXT_NAME && isFlutterDriverCommand(command)) {
215+
if (
216+
this.currentContext === this.NATIVE_CONTEXT_NAME &&
217+
isFlutterDriverCommand(command)
218+
) {
219219
return await super.executeCommand(command, ...args);
220220
}
221221

222222
this.handleContextSwitch(command, args);
223-
logger.default.info(`Executing the proxy command: ${command} with args: ${args}`);
223+
logger.default.info(
224+
`Executing the proxy command: ${command} with args: ${args}`,
225+
);
224226
return await this.proxydriver.executeCommand(command as string, ...args);
225227
}
226228

227229
private handleContextSwitch(command: string, args: any[]): void {
228230
if (command === 'setContext') {
229-
const isWebviewContext = args.find((arg) => typeof arg === 'string' && arg.includes('WEBVIEW'));
230-
this.currentContext = args[0];
231+
const isWebviewContext =
232+
typeof args[0] === 'string' && args[0].includes('WEBVIEW');
233+
if (typeof args[0] === 'string' && args[0].length > 0) {
234+
this.currentContext = args[0];
235+
} else {
236+
logger.default.warn(
237+
`Attempted to set context to invalid value: ${args[0]}. Keeping current context: ${this.currentContext}`,
238+
);
239+
}
240+
231241
if (isWebviewContext) {
232242
this.proxyWebViewActive = true;
233243
} else {
@@ -237,8 +247,8 @@ export class AppiumFlutterDriver extends BaseDriver<FlutterDriverConstraints> {
237247
}
238248

239249
public getProxyAvoidList(): RouteMatcher[] {
240-
return WEBVIEW_NO_PROXY;
241-
}
250+
return WEBVIEW_NO_PROXY;
251+
}
242252

243253
public async createSession(
244254
...args: any[]
@@ -424,14 +434,14 @@ export class AppiumFlutterDriver extends BaseDriver<FlutterDriverConstraints> {
424434
}
425435

426436
public proxyActive(): boolean {
427-
// In WebView context, all request should got to each driver
437+
// In WebView context, all request should go to each driver
428438
// so that they can handle http request properly.
429439
// On iOS, WebView context is handled by XCUITest driver while Android is by chromedriver.
430440
// It means XCUITest driver should keep the XCUITest driver as a proxy,
431441
// while UIAutomator2 driver should proxy to chromedriver instead of UIA2 proxy.
432442
return (
433443
this.proxyWebViewActive &&
434-
this.proxydriver.constructor.name !== XCUITestDriver.name
444+
!(this.proxydriver instanceof XCUITestDriver)
435445
);
436446
}
437447

test/specs/test.e2e.js

Lines changed: 77 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,7 @@ async function performLogin(userName = 'admin', password = '1234') {
55
const att = await browser.flutterByValueKey$('username_text_field');
66
console.log(await att.getAttribute('all'));
77
await browser.flutterByValueKey$('username_text_field').clearValue();
8-
await $(
9-
'//android.view.View[@content-desc="username_text_field"]/android.widget.EditText',
10-
).addValue(userName);
8+
await browser.flutterByValueKey$('username_text_field').addValue(userName);
119

1210
await browser.flutterByValueKey$('password_text_field').clearValue();
1311
await browser.flutterByValueKey$('password').addValue(password);
@@ -21,8 +19,29 @@ async function openScreen(screenTitle) {
2119
await screenListElement.click();
2220
}
2321

22+
async function switchToWebview(timeout = 5000) {
23+
const webviewContext = await browser.waitUntil(
24+
async () => {
25+
const contexts = await browser.getContexts();
26+
return contexts.find((ctx) => ctx.includes('WEBVIEW'));
27+
},
28+
{
29+
timeout,
30+
timeoutMsg: `WEBVIEW context not found within ${timeout / 1000}s`,
31+
},
32+
);
33+
34+
await browser.switchContext(webviewContext);
35+
return webviewContext;
36+
}
37+
2438
describe('My Login application', () => {
2539
afterEach(async () => {
40+
const currentContext = await browser.getContext();
41+
if (currentContext !== 'NATIVE_APP') {
42+
await browser.switchContext('NATIVE_APP');
43+
}
44+
2645
const appID = browser.isIOS
2746
? 'com.example.appiumTestingApp'
2847
: 'com.example.appium_testing_app';
@@ -225,4 +244,59 @@ describe('My Login application', () => {
225244
.getText();
226245
expect(dropped).toEqual('The box is dropped');
227246
});
247+
248+
it('should switch to webview context and validate the page title', async () => {
249+
await performLogin();
250+
await openScreen('Web View');
251+
await switchToWebview();
252+
253+
await browser.waitUntil(
254+
async () => (await browser.getTitle()) === 'Hacker News',
255+
{
256+
timeout: 10000,
257+
timeoutMsg: 'Expected Hacker News title not found',
258+
},
259+
);
260+
261+
const title = await browser.getTitle();
262+
expect(title).toEqual(
263+
'Hacker News',
264+
'Webview title did not match expected',
265+
);
266+
await browser.switchContext('NATIVE_APP');
267+
});
268+
269+
it('should execute native commands correctly while in Webview context', async () => {
270+
await performLogin();
271+
await openScreen('Web View');
272+
await switchToWebview();
273+
274+
// Verify no-proxy native commands still operate while in webview context
275+
const currentContext = await browser.getContext();
276+
expect(currentContext).toContain('WEBVIEW');
277+
278+
const contexts = await browser.getContexts();
279+
expect(Array.isArray(contexts)).toBe(true);
280+
expect(contexts.length).toBeGreaterThan(0);
281+
282+
const windowHandle = await browser.getWindowHandle();
283+
expect(typeof windowHandle).toBe('string');
284+
285+
const pageSource = await browser.getPageSource();
286+
expect(typeof pageSource).toBe('string');
287+
});
288+
289+
it('should switch back and forth between native and Webview contexts', async () => {
290+
await performLogin();
291+
await openScreen('Web View');
292+
293+
await switchToWebview();
294+
expect(await browser.getContext()).toContain('WEBVIEW');
295+
296+
await browser.switchContext('NATIVE_APP');
297+
expect(await browser.getContext()).toBe('NATIVE_APP');
298+
299+
await switchToWebview();
300+
expect(await browser.getContext()).toContain('WEBVIEW');
301+
});
228302
});

wdio.conf.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,8 @@ export const config: Options.Testrunner = {
125125
args: {
126126
basePath: '/wd/hub',
127127
port: 4723,
128-
log: join(process.cwd(), 'appium-logs', 'logs.txt')
128+
log: join(process.cwd(), 'appium-logs', 'logs.txt'),
129+
allowInsecure: 'chromedriver_autodownload',
129130
},
130131
},
131132
],

0 commit comments

Comments
 (0)