Skip to content

Commit f5096ff

Browse files
committed
Working case of optimize waitUntil running per instance + failure msg
UT not finished to be adapted
1 parent 8a8b2f6 commit f5096ff

File tree

4 files changed

+126
-40
lines changed

4 files changed

+126
-40
lines changed

src/matchers/browser/toHaveTitle.ts

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
import type { CompareResult } from '../../utils.js'
21
import { waitUntil, enhanceError, compareText } from '../../utils.js'
32
import { DEFAULT_OPTIONS } from '../../constants.js'
43
import type { MaybeArray } from '../../util/multiRemoteUtil.js'
5-
import { compareMultiRemoteText } from '../../util/multiRemoteUtil.js'
4+
import { getInstancesWithExpected } from '../../util/multiRemoteUtil.js'
5+
import type { BrowserCompareResult } from '../../util/formatMessage.js'
66
import { enhanceMultiRemoteError } from '../../util/formatMessage.js'
77

88
type ExpectedValueType = string | RegExp | WdioAsymmetricMatcher<string>
@@ -34,24 +34,26 @@ export async function toHaveTitle(
3434
})
3535

3636
let actual: string | string[] = ''
37-
let results: CompareResult<string>[] = []
38-
// TODO: dprevost - try to leverage multiple conditions in waitUntil for each remote to not repeat fetch when they succeed.
39-
const pass = await waitUntil(
40-
async () => {
41-
actual = await browser.getTitle()
4237

43-
results = browser.isMultiremote
44-
? compareMultiRemoteText(actual, expectedValue, options)
45-
: [compareText(actual as string, expectedValue as ExpectedValueType, options)]
38+
const browsers = getInstancesWithExpected(browser, expectedValue)
39+
40+
const results: Record<string, BrowserCompareResult> = {}
41+
const conditions = Object.entries(browsers).map(([instance, { browser, expectedValue: expected }]) => async () => {
42+
actual = await browser.getTitle()
4643

47-
return results.map((res) => res.result)
48-
},
44+
const result = compareText(actual, expected as ExpectedValueType, options)
45+
results[instance] = { instance, result }
46+
return result.result
47+
})
48+
49+
const pass = await waitUntil(
50+
conditions,
4951
isNot,
5052
options,
5153
)
5254

5355
const message = browser.isMultiremote
54-
? enhanceMultiRemoteError('window', results, { expectation, verb, isNot }, '', options)
56+
? enhanceMultiRemoteError('window', Object.values(results), { expectation, verb, isNot }, '', options)
5557
: enhanceError('window', expectedValue, actual, this, verb, expectation, '', options)
5658
const result: ExpectWebdriverIO.AssertionResult = {
5759
pass,

src/util/formatMessage.ts

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -85,13 +85,22 @@ export const enhanceError = (
8585
arg2 = ` ${arg2}`
8686
}
8787

88+
/**
89+
* Example of below message:
90+
* Expect window to have title
91+
*
92+
* Expected: "some Title text"
93+
* Received: "some Wrong Title text"
94+
*/
8895
const msg = `${message}Expect ${subject} ${not(isNot)}to ${verb}${expectation}${arg2}${contain}\n\n${diffString}`
8996
return msg
9097
}
9198

99+
export type BrowserCompareResult = { instance: string; result: CompareResult<string> }
100+
92101
export const enhanceMultiRemoteError = (
93102
subject: string | WebdriverIO.Element | WebdriverIO.ElementArray,
94-
compareResults: CompareResult<unknown>[],
103+
compareResults: BrowserCompareResult[],
95104
context: ExpectWebdriverIO.MatcherContext,
96105
arg2 = '',
97106
{ message = '', containing = false }): string => {
@@ -109,12 +118,12 @@ export const enhanceMultiRemoteError = (
109118
if (verb) {
110119
verb += ' '
111120
}
112-
const failedResults = compareResults.filter(result => result.result === isNot)
121+
const failedResults = compareResults.filter(({ result }) => result.result === isNot)
113122

114123
let msg = ''
115-
for (const result of failedResults) {
116-
const actual = result.value
117-
const expected = result.expected
124+
for (const browserResult of failedResults) {
125+
const { value: actual, expected } = browserResult.result
126+
const instanceName = browserResult.instance
118127

119128
let diffString = isNot && equals(actual, expected)
120129
? `${EXPECTED_LABEL}: ${printExpected(expected)}\n${RECEIVED_LABEL}: ${printReceived(actual)}`
@@ -134,7 +143,14 @@ export const enhanceMultiRemoteError = (
134143
arg2 = ` ${arg2}`
135144
}
136145

137-
msg += `${message}Expect ${subject} ${not(isNot)}to ${verb}${expectation}${arg2}${contain}\n\n${diffString}\n\n`
146+
/**
147+
* Example of below message:
148+
* Expect window to have title
149+
*
150+
* Expected: "some Title text"
151+
* Received: "some Wrong Title text"
152+
*/
153+
msg += `${message}Expect ${subject} ${not(isNot)}to ${verb}${expectation}${arg2}${contain} for remote "${instanceName}"\n\n${diffString}\n\n`
138154

139155
}
140156
return msg.trim()

src/util/multiRemoteUtil.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import type { Browser } from 'webdriverio'
12
import type { CompareResult } from '../utils'
23
import { compareText } from '../utils'
34

@@ -44,3 +45,28 @@ export const compareMultiRemoteText = (
4445

4546
return results
4647
}
48+
49+
export const isMultiremote = (browser: WebdriverIO.Browser | WebdriverIO.MultiRemoteBrowser): browser is WebdriverIO.MultiRemoteBrowser => {
50+
return (browser as WebdriverIO.MultiRemoteBrowser).isMultiremote === true
51+
}
52+
53+
export const getInstancesWithExpected = <T>(browsers: WebdriverIO.Browser | WebdriverIO.MultiRemoteBrowser, expectedValues: T): Record<string, { browser: Browser; expectedValue: T; }> => {
54+
if (isMultiremote(browsers)) {
55+
if (Array.isArray(expectedValues)) {
56+
if (expectedValues.length !== browsers.instances.length) {
57+
throw new Error(`Expected values length (${expectedValues.length}) does not match number of browser instances (${browsers.instances.length}) in multiremote setup.`)
58+
}
59+
}
60+
// TODO dprevost add support for object like { default: 'title', browserA: 'titleA', browserB: 'titleB' } later
61+
62+
const browsersWithExpected = browsers.instances.reduce((acc, instance, index) => {
63+
const browser = browsers.getInstance(instance)
64+
const expectedValue = Array.isArray(expectedValues) ? expectedValues[index] : expectedValues
65+
acc[instance] = { browser, expectedValue }
66+
return acc
67+
}, {} as Record<string, { browser: WebdriverIO.Browser, expectedValue: T }>)
68+
return browsersWithExpected
69+
}
70+
71+
return { default: { browser: browsers, expectedValue: expectedValues } }
72+
}

test/matchers/browser/toHaveTitle.test.ts

Lines changed: 63 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,28 @@ import { toHaveTitle } from '../../../src/matchers/browser/toHaveTitle'
55
const beforeAssertion = vi.fn()
66
const afterAssertion = vi.fn()
77

8+
const browserA = { getTitle: vi.fn().mockResolvedValue('browserA Title') } as unknown as WebdriverIO.Browser
9+
const browserB = { getTitle: vi.fn().mockResolvedValue('browserB Title') } as unknown as WebdriverIO.Browser
10+
const multiRemoteBrowserInstances: Record<string, WebdriverIO.Browser> = {
11+
'browserA': browserA,
12+
'browserB': browserB,
13+
}
14+
815
vi.mock('@wdio/globals', () => ({
916
browser: {
1017
getTitle: vi.fn().mockResolvedValue(''),
1118
},
1219
multiremotebrowser: {
1320
isMultiremote: true,
1421
getTitle: vi.fn().mockResolvedValue(['']),
22+
instances: ['browserA'],
23+
getInstance: (name: string) => {
24+
const instance = multiRemoteBrowserInstances[name]
25+
if (!instance) {
26+
throw new Error(`No such instance: ${name}`)
27+
}
28+
return instance
29+
}
1530
}
1631
}))
1732

@@ -103,6 +118,9 @@ Received: "some Wrong Title text"`
103118
describe('Multi Remote Browsers', async () => {
104119
beforeEach(async () => {
105120
multiremotebrowser.getTitle = vi.fn().mockResolvedValue([goodTitle])
121+
multiremotebrowser.instances = ['browserA']
122+
browserA.getTitle = vi.fn().mockResolvedValue(goodTitle)
123+
browserB.getTitle = vi.fn().mockResolvedValue(goodTitle)
106124
})
107125

108126
describe('given default usage', async () => {
@@ -113,11 +131,11 @@ Received: "some Wrong Title text"`
113131
})
114132

115133
test('when failure', async () => {
116-
multiremotebrowser.getTitle = vi.fn().mockResolvedValue([wrongTitle])
134+
browserA.getTitle = vi.fn().mockResolvedValue(wrongTitle)
117135
const result = await defaultContext.toHaveTitle(multiremotebrowser, goodTitle)
118136

119137
expect(result.pass).toBe(false)
120-
expect(result.message()).toEqual(`Expect window to have title
138+
expect(result.message()).toEqual(`Expect window to have title for remote "browserA"
121139
122140
Expected: "some Title text"
123141
Received: "some Wrong Title text"`
@@ -126,6 +144,11 @@ Received: "some Wrong Title text"`
126144
})
127145

128146
describe('given multiple remote browsers', async () => {
147+
beforeEach(async () => {
148+
multiremotebrowser.instances = ['browserA', 'browserB']
149+
browserA.getTitle = vi.fn().mockResolvedValue(goodTitle)
150+
browserB.getTitle = vi.fn().mockResolvedValue(goodTitle)
151+
})
129152

130153
describe('given one expected value', async () => {
131154
const goodTitles = [goodTitle, goodTitle]
@@ -139,29 +162,42 @@ Received: "some Wrong Title text"`
139162
expect(result.pass).toBe(true)
140163
})
141164

142-
test('when failure for one browser', async () => {
143-
multiremotebrowser.getTitle = vi.fn().mockResolvedValue([wrongTitle, goodTitle])
165+
test('when failure for browserA', async () => {
166+
browserA.getTitle = vi.fn().mockResolvedValue(wrongTitle)
167+
const result = await defaultContext.toHaveTitle(multiremotebrowser, goodTitle)
168+
169+
expect(result.pass).toBe(false)
170+
expect(result.message()).toEqual(`Expect window to have title for remote "browserA"
171+
172+
Expected: "some Title text"
173+
Received: "some Wrong Title text"`
174+
)
175+
})
176+
177+
test('when failure for browserB', async () => {
178+
browserB.getTitle = vi.fn().mockResolvedValue(wrongTitle)
144179
const result = await defaultContext.toHaveTitle(multiremotebrowser, goodTitle)
145180

146181
expect(result.pass).toBe(false)
147-
expect(result.message()).toEqual(`Expect window to have title
182+
expect(result.message()).toEqual(`Expect window to have title for remote "browserB"
148183
149184
Expected: "some Title text"
150185
Received: "some Wrong Title text"`
151186
)
152187
})
153188

154189
test('when failure for multiple browsers', async () => {
155-
multiremotebrowser.getTitle = vi.fn().mockResolvedValue([wrongTitle, wrongTitle])
190+
browserA.getTitle = vi.fn().mockResolvedValue(wrongTitle)
191+
browserB.getTitle = vi.fn().mockResolvedValue(wrongTitle)
156192
const result = await defaultContext.toHaveTitle(multiremotebrowser, goodTitle)
157193

158194
expect(result.pass).toBe(false)
159-
expect(result.message()).toEqual(`Expect window to have title
195+
expect(result.message()).toEqual(`Expect window to have title for remote "browserA"
160196
161197
Expected: "some Title text"
162198
Received: "some Wrong Title text"
163199
164-
Expect window to have title
200+
Expect window to have title for remote "browserB"
165201
166202
Expected: "some Title text"
167203
Received: "some Wrong Title text"`
@@ -196,15 +232,15 @@ Received: "some Wrong Title text"`
196232
})
197233

198234
test('when failure', async () => {
199-
multiremotebrowser.getTitle = vi.fn().mockResolvedValue([wrongTitle])
235+
browserA.getTitle = vi.fn().mockResolvedValue(wrongTitle)
200236
const result = await defaultContext.toHaveTitle(
201237
multiremotebrowser,
202238
goodTitle,
203239
options,
204240
)
205241

206242
expect(result.pass).toBe(false)
207-
expect(result.message()).toEqual(`Expect window to have title
243+
expect(result.message()).toEqual(`Expect window to have title for remote "browserA"
208244
209245
Expected: "some title text"
210246
Received: "some wrong title text"`
@@ -226,11 +262,12 @@ Received: "some wrong title text"`
226262

227263
describe('given multiple expected values', async () => {
228264
const goodTitle2 = `${goodTitle} 2`
229-
const goodTitles = [goodTitle, goodTitle2]
265+
// const goodTitles = [goodTitle, goodTitle2]
230266
const expectedValues = [goodTitle, goodTitle2]
231267

232268
beforeEach(async () => {
233-
multiremotebrowser.getTitle = vi.fn().mockResolvedValue(goodTitles)
269+
browserA.getTitle = vi.fn().mockResolvedValue(goodTitle)
270+
browserB.getTitle = vi.fn().mockResolvedValue(goodTitle2)
234271
})
235272

236273
test('when success', async () => {
@@ -240,28 +277,31 @@ Received: "some wrong title text"`
240277
})
241278

242279
test('when failure for one browser', async () => {
243-
multiremotebrowser.getTitle = vi.fn().mockResolvedValue([wrongTitle, goodTitle2])
280+
browserA.getTitle = vi.fn().mockResolvedValue(wrongTitle)
281+
244282
const result = await defaultContext.toHaveTitle(multiremotebrowser, expectedValues)
245283

246284
expect(result.pass).toBe(false)
247-
expect(result.message()).toEqual(`Expect window to have title
285+
expect(result.message()).toEqual(`Expect window to have title for remote "browserA"
248286
249287
Expected: "some Title text"
250288
Received: "some Wrong Title text"`
251289
)
252290
})
253291

254292
test('when failure for multiple browsers', async () => {
255-
multiremotebrowser.getTitle = vi.fn().mockResolvedValue([wrongTitle, wrongTitle])
293+
browserA.getTitle = vi.fn().mockResolvedValue(wrongTitle)
294+
browserB.getTitle = vi.fn().mockResolvedValue(wrongTitle)
295+
256296
const result = await defaultContext.toHaveTitle(multiremotebrowser, expectedValues)
257297

258298
expect(result.pass).toBe(false)
259-
expect(result.message()).toEqual(`Expect window to have title
299+
expect(result.message()).toEqual(`Expect window to have title for remote "browserA"
260300
261301
Expected: "some Title text"
262302
Received: "some Wrong Title text"
263303
264-
Expect window to have title
304+
Expect window to have title for remote "browserB"
265305
266306
Expected: "some Title text 2"
267307
Received: "some Wrong Title text"`
@@ -296,20 +336,22 @@ Received: "some Wrong Title text"`
296336
})
297337

298338
test('when failure', async () => {
299-
multiremotebrowser.getTitle = vi.fn().mockResolvedValue([wrongTitle, wrongTitle])
339+
browserA.getTitle = vi.fn().mockResolvedValue(wrongTitle)
340+
browserB.getTitle = vi.fn().mockResolvedValue(wrongTitle)
341+
300342
const result = await defaultContext.toHaveTitle(
301343
multiremotebrowser,
302344
expectedValues,
303345
options,
304346
)
305347

306348
expect(result.pass).toBe(false)
307-
expect(result.message()).toEqual(`Expect window to have title
349+
expect(result.message()).toEqual(`Expect window to have title for remote "browserA"
308350
309351
Expected: "some title text"
310352
Received: "some wrong title text"
311353
312-
Expect window to have title
354+
Expect window to have title for remote "browserB"
313355
314356
Expected: "some title text 2"
315357
Received: "some wrong title text"`
@@ -416,7 +458,7 @@ Received : "some Title text not expected to be"`
416458
})
417459
})
418460

419-
describe('Multi Remote Browsers', async () => {
461+
describe.skip('Multi Remote Browsers', async () => {
420462
beforeEach(async () => {
421463
multiremotebrowser.getTitle = vi.fn().mockResolvedValue([aTitle])
422464
})

0 commit comments

Comments
 (0)