|
1 | 1 | import { channel, client, onCancel } from '@vitest/browser/client' |
2 | | -import { page, userEvent } from '@vitest/browser/context' |
| 2 | +import { page, server, userEvent } from '@vitest/browser/context' |
3 | 3 | import { collectTests, setupCommonEnv, SpyModule, startCoverageInsideWorker, startTests, stopCoverageInsideWorker } from 'vitest/browser' |
4 | | -import { executor, getBrowserState, getConfig, getWorkerState } from '../utils' |
| 4 | +import { CommandsManager, executor, getBrowserState, getConfig, getWorkerState } from '../utils' |
5 | 5 | import { setupDialogsSpy } from './dialog' |
6 | 6 | import { setupExpectDom } from './expect-element' |
7 | 7 | import { setupConsoleLogSpy } from './logger' |
@@ -34,6 +34,8 @@ async function prepareTestEnvironment(files: string[]) { |
34 | 34 | state.onCancel = onCancel |
35 | 35 | state.rpc = rpc as any |
36 | 36 |
|
| 37 | + getBrowserState().commands = new CommandsManager() |
| 38 | + |
37 | 39 | // TODO: expose `worker` |
38 | 40 | const interceptor = createModuleMockerInterceptor() |
39 | 41 | const mocker = new VitestBrowserClientMocker( |
@@ -69,6 +71,8 @@ async function prepareTestEnvironment(files: string[]) { |
69 | 71 | runner, |
70 | 72 | config, |
71 | 73 | state, |
| 74 | + rpc, |
| 75 | + commands: getBrowserState().commands, |
72 | 76 | } |
73 | 77 | } |
74 | 78 |
|
@@ -113,12 +117,34 @@ async function executeTests(method: 'run' | 'collect', files: string[]) { |
113 | 117 |
|
114 | 118 | debug('runner resolved successfully') |
115 | 119 |
|
116 | | - const { config, runner, state } = preparedData |
| 120 | + const { config, runner, state, commands, rpc } = preparedData |
117 | 121 |
|
118 | 122 | state.durations.prepare = performance.now() - state.durations.prepare |
119 | 123 |
|
120 | 124 | debug('prepare time', state.durations.prepare, 'ms') |
121 | 125 |
|
| 126 | + let contextSwitched = false |
| 127 | + |
| 128 | + // webdiverio context depends on the iframe state, so we need to switch the context, |
| 129 | + // we delay this in case the user doesn't use any userEvent commands to avoid the overhead |
| 130 | + if (server.provider === 'webdriverio') { |
| 131 | + let switchPromise: Promise<void> | null = null |
| 132 | + |
| 133 | + commands.onCommand(async () => { |
| 134 | + if (switchPromise) { |
| 135 | + await switchPromise |
| 136 | + } |
| 137 | + // if this is the first command, make sure we switched the command context to an iframe |
| 138 | + if (!contextSwitched) { |
| 139 | + switchPromise = rpc.wdioSwitchContext('iframe').finally(() => { |
| 140 | + switchPromise = null |
| 141 | + contextSwitched = true |
| 142 | + }) |
| 143 | + await switchPromise |
| 144 | + } |
| 145 | + }) |
| 146 | + } |
| 147 | + |
122 | 148 | try { |
123 | 149 | await Promise.all([ |
124 | 150 | setupCommonEnv(config), |
@@ -151,6 +177,9 @@ async function executeTests(method: 'run' | 'collect', files: string[]) { |
151 | 177 | // need to cleanup for each tester |
152 | 178 | // since playwright keyboard API is stateful on page instance level |
153 | 179 | await userEvent.cleanup() |
| 180 | + if (contextSwitched) { |
| 181 | + await rpc.wdioSwitchContext('parent') |
| 182 | + } |
154 | 183 | } |
155 | 184 | catch (error: any) { |
156 | 185 | await client.rpc.onUnhandledError({ |
|
0 commit comments