Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
83e5f77
delete other packages
jpsantosbh Jul 21, 2025
099fcc8
preparing
jpsantosbh Jul 21, 2025
988b6e6
remove FabricMember
jpsantosbh Jul 21, 2025
c6b294a
remove Fabric
jpsantosbh Jul 21, 2025
b10928c
rename folder
jpsantosbh Jul 21, 2025
6bf0bb1
remove ProgramableCalla
jpsantosbh Jul 22, 2025
e2d0430
partial remove UCall
jpsantosbh Jul 22, 2025
642bf26
remove UCall
jpsantosbh Jul 22, 2025
929c388
cherry pick: 7fbed2eb (upstream/main) BUg Fix: Incoming calls are una…
jpsantosbh Jul 23, 2025
00796e0
Merge pull request #1 from signalwire/joao/renaming
jpsantosbh Aug 6, 2025
a442c28
Merge commit 'e23971bf51626bc7c64ca5990abe4aec6c79ddc1'
jpsantosbh Aug 6, 2025
b192709
temp no cache
jpsantosbh Aug 6, 2025
afdc78b
remove package folders
jpsantosbh Aug 6, 2025
2998cfe
delete package
jpsantosbh Aug 6, 2025
6d3ace2
fix build
jpsantosbh Aug 6, 2025
d712597
Remove workflows and tests for deleted packages
jpsantosbh Aug 6, 2025
e6537bf
Fix e2e test configuration issues
jpsantosbh Aug 6, 2025
f65cc55
Revert "Fix e2e test configuration issues"
jpsantosbh Aug 6, 2025
60b0802
Merge pull request #1272 from signalwire/main
jpsantosbh Aug 6, 2025
c97f250
Merge branch 'main' into joao/merge_back
jpsantosbh Aug 12, 2025
4b79a55
Merge commit 'e7fb6bb9fdcb95a3afa55355b1d85d5e0f51c032' into joao/mer…
jpsantosbh Aug 12, 2025
508617e
Create playground-client package for @signalwire/client
jpsantosbh Aug 13, 2025
6b0a5fb
Fix e2e-client module resolution with Vite config and template updates
jpsantosbh Aug 13, 2025
3801f24
remove unused targets
jpsantosbh Aug 13, 2025
3aee8e4
refactor: Move relayApp.spec.ts to use fixture-based Node.js context
jpsantosbh Aug 13, 2025
ea2fd0b
Update internal/e2e-client/fixtures.ts
jpsantosbh Aug 13, 2025
5fe5a18
Update internal/e2e-client/fixtures.ts
jpsantosbh Aug 13, 2025
3fa0161
Update internal/e2e-client/tests/callfabric/agent_customer.spec.ts
jpsantosbh Aug 13, 2025
8fccca4
Update internal/e2e-client/tests/buildVideoWithFabricSDK.spec.ts
jpsantosbh Aug 13, 2025
4de97ff
Merge branch 'main' into joao/merge_back
jpsantosbh Aug 13, 2025
b6c97ad
Merge branch 'main' into joao/merge_back
jpsantosbh Aug 14, 2025
00d61c2
hardening
jpsantosbh Aug 14, 2025
4d505a0
Merge branch 'joao/quick_fix' into joao/merge_back
jpsantosbh Aug 14, 2025
eb674cd
feat: Simplify dial() API with event listeners support
jpsantosbh Aug 15, 2025
ec87cdd
fix
jpsantosbh Aug 15, 2025
9647410
fix: prevent 'Cannot redefine property' error in WebRTC test setup
jpsantosbh Aug 15, 2025
4603951
fix: Critical fixes for dial() API implementation
jpsantosbh Aug 15, 2025
ca12a92
Merge commit '3e41e57e006a81154185ffdce1ac9cb10deaa6bd' into joao/dia…
jpsantosbh Aug 18, 2025
018908d
fix merge client-e2e
jpsantosbh Aug 18, 2025
f2e4726
revert tsconfig
jpsantosbh Aug 18, 2025
71271ce
revert e2e tests
jpsantosbh Aug 18, 2025
3db030a
revert webrtc setupTest.ts
jpsantosbh Aug 18, 2025
2dd6307
revert reattach
jpsantosbh Aug 18, 2025
acaa0be
add e2e _callState utility
jpsantosbh Aug 19, 2025
aeb90ca
add unit test for CallState test utility
jpsantosbh Aug 28, 2025
6a6e1f9
Merge branch 'main' into joao/dial-with-events
jpsantosbh Aug 28, 2025
0f34e6e
changeset
jpsantosbh Aug 28, 2025
73dde3d
js test
jpsantosbh Sep 2, 2025
ffc4e68
Merge branch 'main' into joao/dial-with-events
jpsantosbh Sep 4, 2025
362f939
revert changes
jpsantosbh Sep 12, 2025
96dcbdd
revert test
jpsantosbh Sep 12, 2025
2fe8fa1
dialer is async
jpsantosbh Sep 12, 2025
76eda13
fix changeset
jpsantosbh Sep 12, 2025
34918a0
Merge commit '570472051f4efde698aa4d64ec9fc40bd487cabd' into joao/dia…
jpsantosbh Sep 12, 2025
427fab7
Fix Merge
jpsantosbh Sep 12, 2025
2373b3c
fix the function signature
jpsantosbh Sep 12, 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
5 changes: 5 additions & 0 deletions .changeset/good-falcons-crash.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@signalwire/client': patch
---

added a `listen` parameter to the Dial funtion allowing developer to pass the event listeners callback and start the call in the `dial()` function.
5 changes: 0 additions & 5 deletions .changeset/twelve-cycles-attack.md

This file was deleted.

1 change: 1 addition & 0 deletions .serena~HEAD
60 changes: 60 additions & 0 deletions internal/e2e-client/CallStateManage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
export class CallStateManager {
public history: any[] = []

constructor() {}

update(event: string, payload: any) {

let safePayload = {}

try {
safePayload = JSON.parse(JSON.stringify(payload))
} catch { }

const timestamp = Date.now()

let newState

if (!event.startsWith('member')) {
newState = {
...this.getState(),
...safePayload,
}
} else {
newState = {
...this.getState(),
}
const memberIndex = newState.room_session.members.findIndex(
(m: any) => m.member_id == payload.member.member_id
)
if (memberIndex >= 0) {
newState.room_session.members[memberIndex] = {
...newState.room_session.members[memberIndex],
...payload.member,
}
}
}

const entry = { event, payload, timestamp, state: newState }

// Add to history
this.history.push(entry)
}

getState() {
return this.history.length
? { ...this.history[this.history.length - 1].state }
: null
}

getSelfState() {
const state = this.getState()
return state?.room_session?.members.find(
(m: any) => m.member_id == state.member_id
)
}

logHistory() {
console.log('Call State History:', JSON.stringify(this.history, null, 2))
}
}
286 changes: 286 additions & 0 deletions internal/e2e-client/CallStateManager.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,286 @@
import { CallStateManager } from './CallStateManage'

describe('CallStateManager', () => {
let callStateManager: CallStateManager

beforeEach(() => {
callStateManager = new CallStateManager()
})

describe('initialization', () => {
it('should initialize with empty history', () => {
expect(callStateManager.history).toEqual([])
})

it('should return null for initial state', () => {
expect(callStateManager.getState()).toBeNull()
})

it('should return undefined for initial self state', () => {
expect(callStateManager.getSelfState()).toBeUndefined()
})
})

describe('update method', () => {
it('should add non-member events to history with updated state', () => {
const event = 'call.joined'
const payload = {
member_id: 'member-123',
room_session: {
members: [],
},
}

callStateManager.update(event, payload)

expect(callStateManager.history).toHaveLength(1)
expect(callStateManager.history[0]).toMatchObject({
event,
payload,
state: payload,
})
expect(callStateManager.history[0].timestamp).toBeDefined()
expect(typeof callStateManager.history[0].timestamp).toBe('number')
})

it('should handle member events by updating member in state', () => {
// First, set up initial state with members
const initialPayload = {
member_id: 'member-123',
room_session: {
members: [
{ member_id: 'member-123', name: 'John', visible: true },
{ member_id: 'member-456', name: 'Jane', visible: true },
],
},
}
callStateManager.update('call.joined', initialPayload)

// Update a member
const memberUpdatePayload = {
member: {
member_id: 'member-123',
visible: false,
muted: true,
},
}
callStateManager.update('member.updated', memberUpdatePayload)

const state = callStateManager.getState()
expect(state.room_session.members).toHaveLength(2)
expect(state.room_session.members[0]).toMatchObject({
member_id: 'member-123',
name: 'John',
visible: false,
muted: true,
})
expect(state.room_session.members[1]).toMatchObject({
member_id: 'member-456',
name: 'Jane',
visible: true,
})
})

it('should preserve history order', () => {
callStateManager.update('event1', { data: 'first' })
callStateManager.update('event2', { data: 'second' })
callStateManager.update('event3', { data: 'third' })

expect(callStateManager.history).toHaveLength(3)
expect(callStateManager.history[0].event).toBe('event1')
expect(callStateManager.history[1].event).toBe('event2')
expect(callStateManager.history[2].event).toBe('event3')
})

it('should merge state for consecutive non-member events', () => {
callStateManager.update('call.joined', {
member_id: '123',
status: 'joined',
})
callStateManager.update('call.updated', { quality: 'HD' })

const state = callStateManager.getState()
expect(state).toMatchObject({
member_id: '123',
status: 'joined',
quality: 'HD',
})
})
})

describe('getState method', () => {
it('should return null when history is empty', () => {
expect(callStateManager.getState()).toBeNull()
})

it('should return a copy of the latest state', () => {
const payload = { test: 'data' }
callStateManager.update('event', payload)

const state1 = callStateManager.getState()
const state2 = callStateManager.getState()

expect(state1).toEqual(payload)
expect(state2).toEqual(payload)
expect(state1).not.toBe(state2) // Should be different object references
})

it('should return the last state after multiple updates', () => {
callStateManager.update('event1', { step: 1 })
callStateManager.update('event2', { step: 2, extra: 'data' })

const state = callStateManager.getState()
expect(state).toMatchObject({
step: 2,
extra: 'data',
})
})
})

describe('getSelfState method', () => {
it('should return undefined when state is null', () => {
expect(callStateManager.getSelfState()).toBeUndefined()
})

it('should return undefined when room_session.members is not present', () => {
callStateManager.update('event', { member_id: '123' })
expect(callStateManager.getSelfState()).toBeUndefined()
})

it('should return the self member from members array', () => {
const payload = {
member_id: 'self-123',
room_session: {
members: [
{ member_id: 'self-123', name: 'Self', role: 'moderator' },
{ member_id: 'other-456', name: 'Other', role: 'participant' },
],
},
}
callStateManager.update('call.joined', payload)

const selfState = callStateManager.getSelfState()
expect(selfState).toMatchObject({
member_id: 'self-123',
name: 'Self',
role: 'moderator',
})
})

it('should return undefined when self member is not found', () => {
const payload = {
member_id: 'self-123',
room_session: {
members: [
{ member_id: 'other-456', name: 'Other', role: 'participant' },
],
},
}
callStateManager.update('call.joined', payload)

expect(callStateManager.getSelfState()).toBeUndefined()
})
})

describe('logHistory method', () => {
it('should log history to console', () => {
const consoleSpy = jest.spyOn(console, 'log').mockImplementation()

callStateManager.update('event1', { data: 'test1' })
callStateManager.update('event2', { data: 'test2' })

callStateManager.logHistory()

expect(consoleSpy).toHaveBeenCalledWith(
'Call State History:',
expect.stringContaining('event1')
)
expect(consoleSpy).toHaveBeenCalledWith(
'Call State History:',
expect.stringContaining('event2')
)

consoleSpy.mockRestore()
})
})

describe('member event handling edge cases', () => {
it('should handle member event when member does not exist in array', () => {
const initialPayload = {
member_id: 'member-123',
room_session: {
members: [{ member_id: 'member-123', name: 'John' }],
},
}
callStateManager.update('call.joined', initialPayload)

// Try to update non-existing member
const memberUpdatePayload = {
member: {
member_id: 'member-999',
visible: false,
},
}
callStateManager.update('member.updated', memberUpdatePayload)

const state = callStateManager.getState()
expect(state.room_session.members).toHaveLength(1)
expect(state.room_session.members[0]).toMatchObject({
member_id: 'member-123',
name: 'John',
})
})

it('should handle member events with empty members array', () => {
const initialPayload = {
member_id: 'member-123',
room_session: {
members: [],
},
}
callStateManager.update('call.joined', initialPayload)

const memberUpdatePayload = {
member: {
member_id: 'member-123',
visible: false,
},
}
callStateManager.update('member.updated', memberUpdatePayload)

const state = callStateManager.getState()
expect(state.room_session.members).toHaveLength(0)
})
})

describe('timestamp handling', () => {
it('should add timestamp to each history entry', () => {
const beforeTimestamp = Date.now()

callStateManager.update('event1', { data: 'test' })

const afterTimestamp = Date.now()

expect(callStateManager.history[0].timestamp).toBeGreaterThanOrEqual(
beforeTimestamp
)
expect(callStateManager.history[0].timestamp).toBeLessThanOrEqual(
afterTimestamp
)
})

it('should have increasing timestamps for consecutive events', (done) => {
callStateManager.update('event1', { data: 'test1' })
const timestamp1 = callStateManager.history[0].timestamp

// Small delay to ensure different timestamp
setTimeout(() => {
callStateManager.update('event2', { data: 'test2' })
const timestamp2 = callStateManager.history[1].timestamp

expect(timestamp2).toBeGreaterThanOrEqual(timestamp1)
done()
}, 1)
})
})
})
4 changes: 2 additions & 2 deletions internal/e2e-client/fixtures.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,19 +57,19 @@
} finally {
console.log('Cleaning up pages..')
/**
* If we have a __callObj in the page means we tested the Video/Fabric APIs
* If we have a __callObj in the page means we tested the Call APIs
* so we must leave the room.
* Invoke `.leave()` only if we have a valid `roomSessionId`.
* Then double check the SDK elements got properly removed from the DOM.
*/
const results = await Promise.all(context.pages().map(leaveRoom))
results.forEach((row) => {
expect(row.videos).toBe(0)

Check failure on line 67 in internal/e2e-client/fixtures.ts

View workflow job for this annotation

GitHub Actions / Browser Client SDK production / Run E2E tests (20.x, default)

[default] › tests/callfabric/incoming_call_over_websocket.spec.ts:6:7 › CallFabric Incoming Call over WebSocket › should handle incoming call via WebSocket between two subscribers

1) [default] › tests/callfabric/incoming_call_over_websocket.spec.ts:6:7 › CallFabric Incoming Call over WebSocket › should handle incoming call via WebSocket between two subscribers Error: expect(received).toBe(expected) // Object.is equality Expected: 0 Received: 1 at ../fixtures.ts:67 65 | const results = await Promise.all(context.pages().map(leaveRoom)) 66 | results.forEach((row) => *** > 67 | expect(row.videos).toBe(0) | ^ 68 | expect(row.rootEl).toBe(0) 69 | ***) 70 | at forEach (/home/runner/work/signalwire-js/signalwire-js/internal/e2e-client/fixtures.ts:67:28) at Object.createCustomPage (/home/runner/work/signalwire-js/signalwire-js/internal/e2e-client/fixtures.ts:66:15)

Check failure on line 67 in internal/e2e-client/fixtures.ts

View workflow job for this annotation

GitHub Actions / Browser Client SDK staging / Run E2E tests (20.x, default)

[default] › tests/callfabric/incoming_call_over_websocket.spec.ts:6:7 › CallFabric Incoming Call over WebSocket › should handle incoming call via WebSocket between two subscribers

2) [default] › tests/callfabric/incoming_call_over_websocket.spec.ts:6:7 › CallFabric Incoming Call over WebSocket › should handle incoming call via WebSocket between two subscribers Error: expect(received).toBe(expected) // Object.is equality Expected: 0 Received: 1 at ../fixtures.ts:67 65 | const results = await Promise.all(context.pages().map(leaveRoom)) 66 | results.forEach((row) => *** > 67 | expect(row.videos).toBe(0) | ^ 68 | expect(row.rootEl).toBe(0) 69 | ***) 70 | at forEach (/home/runner/work/signalwire-js/signalwire-js/internal/e2e-client/fixtures.ts:67:28) at Object.createCustomPage (/home/runner/work/signalwire-js/signalwire-js/internal/e2e-client/fixtures.ts:66:15)

Check failure on line 67 in internal/e2e-client/fixtures.ts

View workflow job for this annotation

GitHub Actions / Browser Client SDK production / Run E2E tests (20.x, callfabric)

[callfabric] › tests/callfabric/incomingCall.spec.ts:6:7 › CallFabric Incoming Call over WebSocket › should handle incoming call via WebSocket between two subscribers

3) [callfabric] › tests/callfabric/incomingCall.spec.ts:6:7 › CallFabric Incoming Call over WebSocket › should handle incoming call via WebSocket between two subscribers Error: expect(received).toBe(expected) // Object.is equality Expected: 0 Received: 1 at ../fixtures.ts:67 65 | const results = await Promise.all(context.pages().map(leaveRoom)) 66 | results.forEach((row) => *** > 67 | expect(row.videos).toBe(0) | ^ 68 | expect(row.rootEl).toBe(0) 69 | ***) 70 | at forEach (/home/runner/work/signalwire-js/signalwire-js/internal/e2e-client/fixtures.ts:67:28) at Object.createCustomPage (/home/runner/work/signalwire-js/signalwire-js/internal/e2e-client/fixtures.ts:66:15)
expect(row.rootEl).toBe(0)
})

/**
* The Call Fabric SDK does not destory the client when the call is finished.
* The Call SDK does not destroy the client when the call is finished.
* Make sure we cleanup the client as well.
*/
await Promise.all(context.pages().map(disconnectClient))
Expand Down
2 changes: 1 addition & 1 deletion internal/e2e-client/utils.ts
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

ignore this changes I will revert them

Original file line number Diff line number Diff line change
Expand Up @@ -526,7 +526,7 @@

const dialer = reattach ? client.reattach : client.dial

const call = dialer({
const call = await dialer({
to: address,
...(shouldPassRootElement && {
rootElement: document.getElementById('rootElement')!,
Expand Down Expand Up @@ -1867,7 +1867,7 @@
timeout: 10_000,
...options,
}
return await expect(assertion, assertionMessage).toPass(mergedOptions)

Check failure on line 1870 in internal/e2e-client/utils.ts

View workflow job for this annotation

GitHub Actions / Browser Client SDK staging / Run E2E tests (20.x, default)

[default] › tests/buildVideoWithFabricSDK.spec.ts:342:7 › buildVideoElement with Call SDK › should handle the element for multiple users

1) [default] › tests/buildVideoWithFabricSDK.spec.ts:342:7 › buildVideoElement with Call SDK › should handle the element for multiple users Error: expect dialAddress to succeed Timeout 15000ms exceeded while waiting on the predicate at ../utils.ts:1870 1868 | ...options, 1869 | *** > 1870 | return await expect(assertion, assertionMessage).toPass(mergedOptions) | ^ 1871 | *** 1872 | /** 1873 | * @description at expectToPass (/home/runner/work/signalwire-js/signalwire-js/internal/e2e-client/utils.ts:1870:52) at expectPageEvalToPass (/home/runner/work/signalwire-js/signalwire-js/internal/e2e-client/utils.ts:1959:9) at dialAddress (/home/runner/work/signalwire-js/signalwire-js/internal/e2e-client/utils.ts:504:10) at /home/runner/work/signalwire-js/signalwire-js/internal/e2e-client/tests/buildVideoWithFabricSDK.spec.ts:371:22

Check failure on line 1870 in internal/e2e-client/utils.ts

View workflow job for this annotation

GitHub Actions / Browser Client SDK staging / Run E2E tests (20.x, callfabric)

[callfabric] › tests/callfabric/holdunhold.spec.ts:15:7 › CallCall Hold/Unhold Call › should dial a call and be able to hold/unhold the call

5) [callfabric] › tests/callfabric/holdunhold.spec.ts:15:7 › CallCall Hold/Unhold Call › should dial a call and be able to hold/unhold the call › [page-two] should create a client and dial a call Error: expect dialAddress to succeed Timeout 15000ms exceeded while waiting on the predicate at ../utils.ts:1870 1868 | ...options, 1869 | *** > 1870 | return await expect(assertion, assertionMessage).toPass(mergedOptions) | ^ 1871 | *** 1872 | /** 1873 | * @description at expectToPass (/home/runner/work/signalwire-js/signalwire-js/internal/e2e-client/utils.ts:1870:52) at expectPageEvalToPass (/home/runner/work/signalwire-js/signalwire-js/internal/e2e-client/utils.ts:1959:9) at dialAddress (/home/runner/work/signalwire-js/signalwire-js/internal/e2e-client/utils.ts:504:10) at /home/runner/work/signalwire-js/signalwire-js/internal/e2e-client/tests/callfabric/holdunhold.spec.ts:37:24 at /home/runner/work/signalwire-js/signalwire-js/internal/e2e-client/tests/callfabric/holdunhold.spec.ts:35:5

Check failure on line 1870 in internal/e2e-client/utils.ts

View workflow job for this annotation

GitHub Actions / Browser Client SDK staging / Run E2E tests (20.x, callfabric)

[callfabric] › tests/callfabric/audioFlags.spec.ts:146:7 › CallCall Audio Flags › should join a room

4) [callfabric] › tests/callfabric/audioFlags.spec.ts:146:7 › CallCall Audio Flags › should join a room, update audio flags for other member, reload and reattach with correct states › [pageTwo] create client and join a room Error: expect dialAddress to succeed Timeout 15000ms exceeded while waiting on the predicate at ../utils.ts:1870 1868 | ...options, 1869 | *** > 1870 | return await expect(assertion, assertionMessage).toPass(mergedOptions) | ^ 1871 | *** 1872 | /** 1873 | * @description at expectToPass (/home/runner/work/signalwire-js/signalwire-js/internal/e2e-client/utils.ts:1870:52) at expectPageEvalToPass (/home/runner/work/signalwire-js/signalwire-js/internal/e2e-client/utils.ts:1959:9) at dialAddress (/home/runner/work/signalwire-js/signalwire-js/internal/e2e-client/utils.ts:504:10) at /home/runner/work/signalwire-js/signalwire-js/internal/e2e-client/tests/callfabric/audioFlags.spec.ts:175:69 at /home/runner/work/signalwire-js/signalwire-js/internal/e2e-client/tests/callfabric/audioFlags.spec.ts:172:7
}
/**
* @description
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"changeset": "changeset",
"clean": "npm exec --ws -- npx rimraf node_modules && npm exec --ws -- npx rimraf dist && npx rimraf node_modules",
"clean:vite-cache": "npx rimraf ./internal/**/node_modules/.vite",
"test": "npm exec --ws npm run test",
"test": "npm exec --ws npm run test && npx jest internal/e2e-client/*.test.ts",
Copy link
Collaborator

Choose a reason for hiding this comment

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

This looks like a mistake?

Copy link
Collaborator

Choose a reason for hiding this comment

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

There are no jest tests in internal/e2e-client.

"build": "npm run clean:vite-cache && npm exec --ws -- npx rimraf dist && sw-build-all",
"prettier": "prettier --write .",
"release:dev": "sw-release --development",
Expand Down
Loading
Loading