Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
66 commits
Select commit Hold shift + click to select a range
d89013b
export the CustomPage type
LittorWired Aug 14, 2025
047474e
add _callObj to the global window type
LittorWired Aug 14, 2025
754ba67
throw if call object not found
LittorWired Aug 14, 2025
1902caa
refactor expectLayoutChanged to use expectToPass utility
LittorWired Aug 14, 2025
e0c8d77
expectToPass util wrapper
LittorWired Aug 14, 2025
0017cd3
waitForFunction e2e util wrapper
LittorWired Aug 14, 2025
792b477
refactor setLayoutOnPage to use waitForFunction util
LittorWired Aug 14, 2025
9ad8353
Add unit tests for expectToPass utility in utils.spec.ts
LittorWired Aug 14, 2025
6dfd8e6
refactor videoRoom.spec.ts to use expectToPass and waitForFunction ut…
LittorWired Aug 14, 2025
36e8b3c
reassign top-level callSession and have sanity check to assert that v…
LittorWired Aug 15, 2025
acbe7a4
fix up old ts errors to return the proper page "type"
LittorWired Aug 15, 2025
847ae6c
update DialAddress return type to allow generic
LittorWired Aug 18, 2025
24d4fde
Add assertions to ensure SAT token, SignalWire, API token, and Relay …
LittorWired Aug 18, 2025
3836329
revert throw
LittorWired Aug 18, 2025
a126d6d
cannot use expect inside of page.evaluate so throw instead
LittorWired Aug 18, 2025
97a4b19
Added checks for callObj existence before usage. update ts-expect-err…
LittorWired Aug 18, 2025
b02eace
add return type
LittorWired Aug 18, 2025
abc8c44
throw if not call obj
LittorWired Aug 18, 2025
2a709f2
do not poll for expectToPass and waitForFunction
LittorWired Aug 18, 2025
8ae0931
add expectPageEvalToPass wrapper
LittorWired Aug 18, 2025
725feab
update description and add custom assertion
LittorWired Aug 18, 2025
d18ff6d
refactor the videoRoom.spec.ts to use refactor expectPageEvalToPass p…
LittorWired Aug 18, 2025
7433d9a
refactor the utils to use the expectPageEvalToPass pattern where appl…
LittorWired Aug 18, 2025
beb0335
PR feedback: use CallJoinedEventParams from signalwire/client
LittorWired Aug 19, 2025
bbe88b8
PR feedback: check expected properties for sanity check
LittorWired Aug 19, 2025
249c2e8
PR feedback: remove the intercepWsTraffic package in fixtures
LittorWired Aug 19, 2025
52bad3a
PR feedback remove playwrigth-ws-inspector @sw-internal/e2e-client
LittorWired Aug 19, 2025
077c699
PR: feedback, remove unused try/catch block
LittorWired Aug 19, 2025
58a0e79
Merge remote-tracking branch 'origin/main' into tl/cp-15822-use-waitF…
LittorWired Aug 19, 2025
74c2a8a
PR feedback: revert the return of dialAddress type
LittorWired Aug 19, 2025
4c16a8c
remove unused type
LittorWired Aug 19, 2025
4e5af63
format
LittorWired Aug 19, 2025
18e97b4
Refactor expectPageEvalToPass to accept an array for interval and ret…
LittorWired Aug 19, 2025
19ce61a
PR feedback: refactor to take advantage of return value
LittorWired Aug 19, 2025
8ed1139
remove unused util expectScreenShareJoined
LittorWired Aug 20, 2025
6c853cf
refactor setLayoutOnPage to use expectPageEvalToPass util
LittorWired Aug 20, 2025
a5d5d13
mark TODO for utils that are not utilize for removal
LittorWired Aug 20, 2025
e166eed
PR feedback: expectToPass assertionMessage param to follow expect type
LittorWired Aug 20, 2025
a392b05
update existing utils utilize return value
LittorWired Aug 20, 2025
9439667
PR feedback: provide better JSDocs comments for new utils
LittorWired Aug 20, 2025
1b4a264
PR feedback: use line reporter
LittorWired Aug 20, 2025
04cc22a
PR feedback: type assertion to force return type to avoid undefined c…
LittorWired Aug 20, 2025
e38eb42
PR feedback: revert dialAddress type return. Refactor dialAddress uti…
LittorWired Aug 20, 2025
0999049
assign the return type from dialAddress
LittorWired Aug 20, 2025
b49465a
PR feedback: revert reporter changes
LittorWired Aug 20, 2025
f4b65d1
PR feedback: add TODO and addition tests for new util tests
LittorWired Aug 20, 2025
1c82493
PR feedback: fix assertion message. make assert callback mandatory
LittorWired Aug 25, 2025
3be9338
Refactor videoRoom.spec.ts to unify assertion messages and enforce ma…
LittorWired Aug 26, 2025
208c959
fix lint error dialAddress utility to support generic return types
LittorWired Aug 26, 2025
3f448af
Enhance assertion messages in videoRoom.spec.ts for clarity and consi…
LittorWired Aug 26, 2025
68de21c
Enhance assertion messages in utils.ts for improved clarity and consi…
LittorWired Aug 26, 2025
5a0c08a
fix the return type for dialAddress to default to any but allow generic
LittorWired Aug 26, 2025
ad1cc01
Refactor expectPageEvalToPass tests to unify assertion messages and e…
LittorWired Aug 26, 2025
f02774d
Refactor utils.spec.ts to enhance error message assertions and add ne…
LittorWired Aug 26, 2025
2153dfd
PR feedback: refactor waitForFunction params to be consistent with ex…
LittorWired Aug 26, 2025
a39b9b9
Refactor waitForFunction calls in videoRoom.spec.ts to standardize pa…
LittorWired Aug 26, 2025
9656599
remove only
LittorWired Aug 26, 2025
912aa1d
increase timeout duration and assert result is undefined
LittorWired Aug 26, 2025
76866bd
Update GitHub workflows to include 'default' project in the build mat…
LittorWired Aug 26, 2025
ee7f653
remove result assertion
LittorWired Aug 26, 2025
6f834a3
Add timeout test for promise resolution and refine assertion messages…
LittorWired Aug 26, 2025
e5b51dc
Refactor error handling in expectPageEvalToPass test to ensure proper…
LittorWired Aug 26, 2025
65402ee
remove only
LittorWired Aug 26, 2025
b9bee74
Update evaluateFn in expectPageEvalToPass test to return a rejected p…
LittorWired Aug 26, 2025
0dfd2e5
remove only
LittorWired Aug 26, 2025
94be26a
await the assertion promise
LittorWired Aug 26, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/browser-client-production.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
fail-fast: false
matrix:
node-version: [20.x]
project: [callfabric, renegotiation, videoElement]
project: [default, callfabric, renegotiation, videoElement]
steps:
- uses: actions/checkout@v4
- name: Install deps
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/browser-client-staging.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
fail-fast: false
matrix:
node-version: [20.x]
project: [callfabric, renegotiation, videoElement]
project: [default, callfabric, renegotiation, videoElement]
steps:
- uses: actions/checkout@v4
- name: Install deps
Expand Down
20 changes: 6 additions & 14 deletions internal/e2e-client/fixtures.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { PageWithWsInspector, intercepWsTraffic } from 'playwrigth-ws-inspector'
import { test as baseTest, expect, type Page } from '@playwright/test'
import {
CreatecXMLScriptParams,
Expand All @@ -22,9 +21,7 @@ type CustomPage = Page & {
swNetworkUp: () => Promise<void>
}
type CustomFixture = {
createCustomPage(options: {
name: string
}): Promise<PageWithWsInspector<CustomPage>>
createCustomPage(options: { name: string }): Promise<CustomPage>
createCustomVanillaPage(options: { name: string }): Promise<Page>
resource: {
createcXMLExternalURLResource: typeof createcXMLExternalURLResource
Expand All @@ -38,25 +35,20 @@ type CustomFixture = {

const test = baseTest.extend<CustomFixture>({
createCustomPage: async ({ context }, use) => {
const maker = async (options: {
name: string
}): Promise<PageWithWsInspector<CustomPage>> => {
let page = await context.newPage()
const maker = async (options: { name: string }): Promise<CustomPage> => {
const page = (await context.newPage()) as CustomPage
enablePageLogs(page, options.name)
//@ts-ignore
page = await intercepWsTraffic(page)

// @ts-expect-error
page.swNetworkDown = () => {
console.log('Simulate network down..')
return context.setOffline(true)
}
// @ts-expect-error

page.swNetworkUp = () => {
console.log('Simulate network up..')
return context.setOffline(false)
}
// @ts-expect-error

return page
}

Expand Down Expand Up @@ -145,4 +137,4 @@ const test = baseTest.extend<CustomFixture>({
},
})

export { test, expect, Page }
export { test, expect, Page, CustomPage }
1 change: 0 additions & 1 deletion internal/e2e-client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
"devDependencies": {
"@playwright/test": "^1.52.0",
"@types/express": "^5.0.1",
"playwrigth-ws-inspector": "^1.0.0",
"vite": "^7.0.0"
}
}
313 changes: 313 additions & 0 deletions internal/e2e-client/tests/callfabric/utils.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,313 @@
import { expectPageEvalToPass, expectToPass, SERVER_URL } from '../../utils'
import { test, expect } from '../../fixtures'

test.describe('utils', () => {
test.describe('expectToPass', () => {
test('expectToPass: should resolve when the function passes', async ({
createCustomPage,
}) => {
const page = await createCustomPage({ name: '[page]' })
await page.goto(SERVER_URL)

await expectToPass(
async () => {
const result = await page.waitForFunction(() => true)
expect(await result.jsonValue()).toBe(true)
},
{ message: 'should resolve when the function passes' }
)
})

test('should fail with a custom message and stack trace', async ({
createCustomPage,
}) => {
let expectedError: Error | undefined = undefined
const page = await createCustomPage({ name: '[page]' })
await page.goto(SERVER_URL)

try {
await expectToPass(
async () => {
await page.waitForFunction(() => {
throw new Error('test error')
})
},
{ message: 'custom message' }
)
} catch (error) {
expectedError = error
}
expect(expectedError).toBeDefined()
expect(expectedError).toBeInstanceOf(Error)
expect(expectedError).toMatchObject({
message: expect.stringContaining('custom message'),
stack: expect.stringContaining('utils.spec.ts'),
})
})

test('should timeout when waiting for a promise to resolve', async () => {
expect(
expectToPass(
async () => {
await new Promise((resolve) => setTimeout(resolve, 1000))
},
{ message: 'expect timeout' },
{ timeout: 100 }
)
).rejects.toThrow('Timeout 100ms exceeded while waiting on the predicate')
})

test('should respect custom timeout option', async ({
createCustomPage,
}) => {
const page = await createCustomPage({ name: '[page]' })

const startTime = Date.now()
let expectedError: Error | undefined = undefined

try {
await expectToPass(
async () => {
await page.waitForTimeout(3000) // Delay longer than timeout
expect(false).toBe(true) // Will never pass
},
{ message: 'should timeout in 1 second' },
{ timeout: 1000 } // Short timeout
)
} catch (error) {
expectedError = error
}

const elapsedTime = Date.now() - startTime
expect(expectedError).toBeDefined()
expect(elapsedTime).toBeLessThan(2000) // Should timeout quickly
})

test('should use custom interval array', async ({ createCustomPage }) => {
const page = await createCustomPage({ name: '[page]' })
await page.goto(SERVER_URL)

let attemptCount = 0
const attempts: number[] = []

await expectToPass(
async () => {
attempts.push(Date.now())
attemptCount++
if (attemptCount < 3) {
throw new Error('Not ready yet')
}
// Pass on 3rd attempt
},
{ message: 'should use custom intervals' },
{ interval: [100, 200, 300], timeout: 10000 }
)

expect(attemptCount).toBe(3)
expect(attempts.length).toBe(3)
})

test('should use default options when none provided', async () => {
let attemptCount = 0

await expectToPass(
async () => {
attemptCount++
if (attemptCount < 2) {
throw new Error('Not ready yet')
}
// Pass on 2nd attempt
},
{ message: 'should use defaults' }
// No options parameter
)

expect(attemptCount).toBe(2)
})

test('should handle immediate success without retries', async () => {
let attemptCount = 0

await expectToPass(
async () => {
attemptCount++
// Succeeds immediately
expect(true).toBe(true)
},
{ message: 'should succeed immediately' }
)

expect(attemptCount).toBe(1) // Should only run once
})

test('should handle promise rejection properly', async () => {
let expectedError: Error | undefined = undefined

try {
await expectToPass(
async () => {
return Promise.reject(new Error('Async rejection'))
},
{ message: 'should handle rejection' },
{ timeout: 1000 }
)
} catch (error) {
expectedError = error
}

expect(expectedError).toBeDefined()
expect(expectedError?.message).toMatch(/should handle rejection/)
})

test('should handle longer polling scenarios', async () => {
let attemptCount = 0
const startTime = Date.now()

await expectToPass(
async () => {
attemptCount++
// Simulate waiting for a condition that takes time
if (Date.now() - startTime < 2000) {
throw new Error('Still waiting...')
}
expect(attemptCount).toBeGreaterThan(1)
},
{ message: 'should handle longer polling' },
{ timeout: 5000 }
)

expect(attemptCount).toBeGreaterThan(1)
})
})
})
Copy link
Collaborator

Choose a reason for hiding this comment

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

Highly appreciate all these utility tests.

Should we add TODO or tests for the other new utilities such as waitForFunction or expectPageEvalToPass?


test.describe('waitForFunction', () => {
test('TODO: should resolve when the function returns a truthy value', async () => {
test.skip(
true,
'TODO: Implement test for waitForFunction resolving on truthy value'
)
})

test('TODO: should timeout if the function never returns truthy', async () => {
test.skip(true, 'TODO: Implement test for waitForFunction timeout behavior')
})

test('TODO: should pass arguments to the page function', async () => {
test.skip(true, 'TODO: Implement test for waitForFunction argument passing')
})
})

test.describe('expectPageEvalToPass', () => {
test('should resolve when the page evaluation passes', async ({
createCustomPage,
}) => {
const page = await createCustomPage({ name: '[page]' })

const result = await expectPageEvalToPass(page, {
assertionFn: (result) => {
expect(result).toBe(true)
},
evaluateFn: () => true,
message: 'pass - resolve when the function returns a truthy value',
})

expect(result).toBe(true)

// with promise
const result2 = await expectPageEvalToPass(page, {
assertionFn: (result) => {
expect(result).toBe(true)
},
evaluateFn: () => Promise.resolve(true),
message: 'pass - resolve when the function returns a truthy value',
})
expect(result2).toBe(true)
})

test('should throw when the evaluateFn throws an error', async ({
createCustomPage,
}) => {
const page = await createCustomPage({ name: '[page]' })

await expect(
expectPageEvalToPass(page, {
assertionFn: (result: unknown) => {
// should not be called because the evaluateFn throws an error
expect(result).not.toBeInstanceOf(Error)
expect(result).not.toMatchObject({
message: 'test error',
})
// should never pass to ensure expect().toPass() does not resolve
expect(false).toBe(true)
},
evaluateFn: () => {
return new Promise((_resolve, reject) => {
setTimeout(() => {
reject(new Error('test error'))
}, 100)
})
},
message: 'expect error',
})
).rejects.toThrow('expect error')
})

test('should pass evaluateArgs to the evaluateFn and return the serializable object', async ({
createCustomPage,
}) => {
const page = await createCustomPage({ name: '[page]' })

const result = await expectPageEvalToPass(page, {
assertionFn: (result) => {
expect(result).toMatchObject({
param: 'test',
param2: false,
param3: 123,
param4: {},
})
},
evaluateArgs: {
param: 'test',
param2: false,
param3: 123,
param4: {},
},
evaluateFn: (params) => {
return params
},
message: 'pass - resolve when the function returns a truthy value',
})

expect(result).toMatchObject({
param: 'test',
param2: false,
param3: 123,
param4: {},
})
})

test('should timeout when page evaluation takes too long', async ({
createCustomPage,
}) => {
const page = await createCustomPage({ name: '[page]' })

await expect(
expectPageEvalToPass(page, {
assertionFn: (result) => {
// should never be called
expect(result).not.toMatch('should not resolve')
},
evaluateFn: () => {
return new Promise((resolve) =>
setTimeout(() => resolve('should not resolve'), 5000)
)
},
message: 'timeout - should timeout when page evaluation takes too long',
timeoutMs: 100,
})
).rejects.toThrow(
'timeout - should timeout when page evaluation takes too long'
)
})
})
Loading
Loading