Skip to content

Commit db75c1c

Browse files
committed
refactor backend client
1 parent 2a5f53b commit db75c1c

File tree

8 files changed

+127
-71
lines changed

8 files changed

+127
-71
lines changed
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { evaluateInFrameContext } from '../helpers/evaluate_in_frame_context'
2+
import type { Protocol } from 'devtools-protocol'
3+
import type { SendDebuggerCommand } from '../../browsers/cdp_automation'
4+
import type { Client as WebDriverClient } from 'webdriver'
5+
6+
const expressionToEvaluate = `window.document.title`
7+
8+
export async function cdpGetFrameTitle (send: SendDebuggerCommand, contexts: Map<Protocol.Runtime.ExecutionContextId, Protocol.Runtime.ExecutionContextDescription>, frame: Protocol.Page.Frame): Promise<string> {
9+
return (await evaluateInFrameContext(expressionToEvaluate, send, contexts, frame!))?.result?.value
10+
}
11+
12+
export async function bidiGetFrameTitle (webDriverClient: WebDriverClient, autContextId: string): Promise<string> {
13+
return (await webDriverClient.scriptEvaluate({
14+
expression: expressionToEvaluate,
15+
target: {
16+
context: autContextId,
17+
},
18+
awaitPromise: false,
19+
// @ts-expect-error - result is not typed
20+
}))?.result?.value
21+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { evaluateInFrameContext } from '../helpers/evaluate_in_frame_context'
2+
import type { Protocol } from 'devtools-protocol'
3+
import type { Client as WebDriverClient } from 'webdriver'
4+
import type { SendDebuggerCommand } from '../../browsers/cdp_automation'
5+
6+
export async function cdpGetUrl (send: SendDebuggerCommand, contexts: Map<Protocol.Runtime.ExecutionContextId, Protocol.Runtime.ExecutionContextDescription>, frame: Protocol.Page.Frame): Promise<string> {
7+
return (await evaluateInFrameContext(`window.location.href`, send, contexts, frame!))?.result?.value
8+
}
9+
10+
export async function bidiGetUrl (webDriverClient: WebDriverClient, autContextId: string): Promise<string> {
11+
const { contexts: autContext } = await webDriverClient.browsingContextGetTree({
12+
root: autContextId,
13+
})
14+
15+
return autContext ? autContext[0].url : ''
16+
}

packages/server/lib/automation/commands/key_press.ts

Lines changed: 2 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ import type { KeyPressParams, KeyPressSupportedKeys } from '@packages/types'
33
import type { SendDebuggerCommand } from '../../browsers/cdp_automation'
44
import type { Client } from 'webdriver'
55
import Debug from 'debug'
6-
import { isEqual, isError } from 'lodash'
7-
import type ProtocolMapping from 'devtools-protocol/types/protocol-mapping'
6+
import { isEqual } from 'lodash'
7+
import { evaluateInFrameContext } from '../helpers/evaluate_in_frame_context'
88

99
const debug = Debug('cypress:server:automation:command:keypress')
1010

@@ -30,28 +30,6 @@ export const CDP_KEYCODE: KeyCodeLookup = {
3030
'Tab': 'U+000009',
3131
}
3232

33-
export async function evaluateInFrameContext (expression: string,
34-
send: SendDebuggerCommand,
35-
contexts: Map<Protocol.Runtime.ExecutionContextId, Protocol.Runtime.ExecutionContextDescription>,
36-
frame: Protocol.Page.Frame): Promise<ProtocolMapping.Commands['Runtime.evaluate']['returnType']> {
37-
for (const [contextId, context] of contexts.entries()) {
38-
if (context.auxData?.frameId === frame.id) {
39-
try {
40-
return await send('Runtime.evaluate', {
41-
expression,
42-
contextId,
43-
})
44-
} catch (e) {
45-
if (isError(e) && (e as Error).message.includes('Cannot find context with specified id')) {
46-
debug('found invalid context %d, removing', contextId)
47-
contexts.delete(contextId)
48-
}
49-
}
50-
}
51-
}
52-
throw new Error('Unable to find valid context for frame')
53-
}
54-
5533
export async function cdpKeyPress (
5634
{ key }: KeyPressParams, send: SendDebuggerCommand,
5735
contexts: Map<Protocol.Runtime.ExecutionContextId, Protocol.Runtime.ExecutionContextDescription>,
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { evaluateInFrameContext } from '../helpers/evaluate_in_frame_context'
2+
import type { Protocol } from 'devtools-protocol'
3+
import type { SendDebuggerCommand } from '../../browsers/cdp_automation'
4+
import type { Client as WebDriverClient } from 'webdriver'
5+
6+
const expressionToEvaluate = (historyNumber: number) => `window.history.go(${historyNumber})`
7+
8+
export async function cdpNavigateHistory (send: SendDebuggerCommand, contexts: Map<Protocol.Runtime.ExecutionContextId, Protocol.Runtime.ExecutionContextDescription>, frame: Protocol.Page.Frame, historyNumber: number): Promise<void> {
9+
await evaluateInFrameContext(expressionToEvaluate(historyNumber), send, contexts, frame)
10+
}
11+
12+
export async function bidiNavigateHistory (webDriverClient: WebDriverClient, autContextId: string, historyNumber: number): Promise<void> {
13+
await webDriverClient.scriptEvaluate({
14+
expression: expressionToEvaluate(historyNumber),
15+
target: {
16+
context: autContextId,
17+
},
18+
awaitPromise: false,
19+
})
20+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { evaluateInFrameContext } from '../helpers/evaluate_in_frame_context'
2+
import type { Protocol } from 'devtools-protocol'
3+
import type { SendDebuggerCommand } from '../../browsers/cdp_automation'
4+
import type { Client as WebDriverClient } from 'webdriver'
5+
6+
const expressionToEvaluate = (forceReload = false) => `window.location.reload(${forceReload})`
7+
8+
export async function cdpReloadFrame (send: SendDebuggerCommand, contexts: Map<Protocol.Runtime.ExecutionContextId, Protocol.Runtime.ExecutionContextDescription>, frame: Protocol.Page.Frame, forceReload: boolean): Promise<void> {
9+
await evaluateInFrameContext(expressionToEvaluate(forceReload), send, contexts, frame)
10+
}
11+
12+
export async function bidiReloadFrame (webDriverClient: WebDriverClient, autContextId: string, forceReload: boolean): Promise<void> {
13+
await webDriverClient.scriptEvaluate({
14+
expression: expressionToEvaluate(forceReload),
15+
target: {
16+
context: autContextId,
17+
},
18+
awaitPromise: false,
19+
})
20+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import type { Protocol } from 'devtools-protocol'
2+
import type { SendDebuggerCommand } from '../../browsers/cdp_automation'
3+
import Debug from 'debug'
4+
import { isError } from 'lodash'
5+
import type ProtocolMapping from 'devtools-protocol/types/protocol-mapping'
6+
7+
const debug = Debug('cypress:server:automation:helpers:evaluate_in_frame_context')
8+
9+
export async function evaluateInFrameContext (expression: string,
10+
send: SendDebuggerCommand,
11+
contexts: Map<Protocol.Runtime.ExecutionContextId, Protocol.Runtime.ExecutionContextDescription>,
12+
frame: Protocol.Page.Frame): Promise<ProtocolMapping.Commands['Runtime.evaluate']['returnType']> {
13+
for (const [contextId, context] of contexts.entries()) {
14+
if (context.auxData?.frameId === frame.id) {
15+
try {
16+
return await send('Runtime.evaluate', {
17+
expression,
18+
contextId,
19+
})
20+
} catch (e) {
21+
if (isError(e) && (e as Error).message.includes('Cannot find context with specified id')) {
22+
debug('found invalid context %d, removing', contextId)
23+
contexts.delete(contextId)
24+
}
25+
}
26+
}
27+
}
28+
throw new Error('Unable to find valid context for frame')
29+
}

packages/server/lib/browsers/bidi_automation.ts

Lines changed: 8 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ import type {
2121
NetworkSameSite,
2222
} from 'webdriver/build/bidi/localTypes'
2323
import type { CyCookie } from './webkit-automation'
24+
import { bidiGetUrl } from '../automation/commands/get_url'
25+
import { bidiReloadFrame } from '../automation/commands/reload_frame'
26+
import { bidiNavigateHistory } from '../automation/commands/navigate_history'
27+
import { bidiGetFrameTitle } from '../automation/commands/get_frame_title'
2428

2529
const BIDI_DEBUG_NAMESPACE = 'cypress:server:browsers:bidi_automation'
2630
const BIDI_COOKIE_DEBUG_NAMESPACE = `${BIDI_DEBUG_NAMESPACE}:cookies`
@@ -662,11 +666,7 @@ export class BidiAutomation {
662666
case 'get:aut:url':
663667
{
664668
if (this.autContextId) {
665-
const { contexts: autContext } = await this.webDriverClient.browsingContextGetTree({
666-
root: this.autContextId,
667-
})
668-
669-
return autContext ? autContext[0].url : ''
669+
return bidiGetUrl(this.webDriverClient, this.autContextId)
670670
}
671671

672672
throw new Error('Cannot get AUT url: no AUT context initialized')
@@ -675,13 +675,7 @@ export class BidiAutomation {
675675
case 'reload:aut:frame':
676676
{
677677
if (this.autContextId) {
678-
await this.webDriverClient.scriptEvaluate({
679-
expression: `window.location.reload(${data.forceReload || false})`,
680-
target: {
681-
context: this.autContextId,
682-
},
683-
awaitPromise: false,
684-
})
678+
await bidiReloadFrame(this.webDriverClient, this.autContextId, data.forceRelease)
685679

686680
return
687681
}
@@ -691,32 +685,15 @@ export class BidiAutomation {
691685
case 'navigate:aut:history':
692686
{
693687
if (this.autContextId) {
694-
await this.webDriverClient.scriptEvaluate({
695-
expression: `window.history.go(${data.historyNumber})`,
696-
target: {
697-
context: this.autContextId,
698-
},
699-
awaitPromise: false,
700-
})
701-
702-
return
688+
await bidiNavigateHistory(this.webDriverClient, this.autContextId, data.historyNumber)
703689
}
704690

705691
throw new Error('Cannot navigate AUT frame history: no AUT context initialized')
706692
}
707693
case 'get:aut:title':
708694
{
709695
if (this.autContextId) {
710-
// @ts-expect-error - result is not typed
711-
const { result } = await this.webDriverClient.scriptEvaluate({
712-
expression: `window.document.title`,
713-
target: {
714-
context: this.autContextId,
715-
},
716-
awaitPromise: false,
717-
})
718-
719-
return result.value
696+
return bidiGetFrameTitle(this.webDriverClient, this.autContextId)
720697
}
721698

722699
throw new Error('Cannot get AUT title no AUT context initialized')

packages/server/lib/browsers/cdp_automation.ts

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,11 @@ import type { CDPClient, ProtocolManagerShape, WriteVideoFrame, AutomationMiddle
1414
import type { Automation } from '../automation'
1515
import { cookieMatches, CyCookie, CyCookieFilter } from '../automation/util'
1616
import { DEFAULT_NETWORK_ENABLE_OPTIONS, CriClient } from './cri-client'
17-
import { cdpKeyPress, evaluateInFrameContext } from '../automation/commands/key_press'
17+
import { cdpKeyPress } from '../automation/commands/key_press'
18+
import { cdpGetUrl } from '../automation/commands/get_url'
19+
import { cdpReloadFrame } from '../automation/commands/reload_frame'
20+
import { cdpNavigateHistory } from '../automation/commands/navigate_history'
21+
import { cdpGetFrameTitle } from '../automation/commands/get_frame_title'
1822

1923
export type CdpCommand = keyof ProtocolMapping.Commands
2024

@@ -476,16 +480,6 @@ export class CdpAutomation implements CDPClient, AutomationMiddleware {
476480
}
477481
}
478482

479-
private _getAutUrl = async () => {
480-
const frame = await this._getAutFrame()
481-
482-
if (!frame) {
483-
throw new Error('Could not find AUT frame')
484-
}
485-
486-
return ((frame?.url || '') + (frame?.urlFragment || '')) || ''
487-
}
488-
489483
_handlePausedRequests = async (client: CriClient) => {
490484
// NOTE: only supported in chromium based browsers
491485
await client.send('Fetch.enable', {
@@ -637,26 +631,27 @@ export class CdpAutomation implements CDPClient, AutomationMiddleware {
637631
{
638632
const frame = await this._getAutFrame()
639633

640-
return (await evaluateInFrameContext(`window.location.href`, this.sendDebuggerCommandFn, this.executionContexts, frame!))?.result?.value
634+
return cdpGetUrl(this.sendDebuggerCommandFn, this.executionContexts, frame!)
641635
}
642636
case 'reload:aut:frame':
643637
{
644638
const frame = await this._getAutFrame()
645639

646-
return evaluateInFrameContext(`window.location.reload(${data.forceReload || false})`, this.sendDebuggerCommandFn, this.executionContexts, frame!)
640+
await cdpReloadFrame(this.sendDebuggerCommandFn, this.executionContexts, frame!, data.forceReload)
641+
642+
return
647643
}
648644
case 'navigate:aut:history':
649645
{
650646
const frame = await this._getAutFrame()
651647

652-
return evaluateInFrameContext(`window.history.go(${data.historyNumber})`, this.sendDebuggerCommandFn, this.executionContexts, frame!)
648+
return cdpNavigateHistory(this.sendDebuggerCommandFn, this.executionContexts, frame!, data.historyNumber!)
653649
}
654-
655650
case 'get:aut:title':
656651
{
657652
const frame = await this._getAutFrame()
658653

659-
return (await evaluateInFrameContext(`window.document.title`, this.sendDebuggerCommandFn, this.executionContexts, frame!))?.result?.value
654+
return cdpGetFrameTitle(this.sendDebuggerCommandFn, this.executionContexts, frame!)
660655
}
661656
default:
662657
throw new Error(`No automation handler registered for: '${message}'`)

0 commit comments

Comments
 (0)