Update tests for Story 5-1 Full AV Replacement

- Mark Story 5-1 as done in sprint-status.yaml
- Update FoundryAdapter.test.js:
  - Updated probeCapability tests to expect 'stream-access' (was 'css-fallback')
  - Added tests for all 11 new buildWebRTCSurface methods
  - Added input validation tests for userId-taking methods
- Update ScryingPoolStrip.test.js:
  - Added tests for hasStreamAccess flag in buildParticipantList
  - Added tests for hasStreamAccess in getData()
  - Added tests for _attachVideoStream() method
  - Added tests for _cleanupVideoStreams() method

All 892 unit tests passing + 7 integration tests passing

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
This commit is contained in:
2026-05-24 12:36:52 +02:00
parent f8cbb75773
commit 25dd427a59
3 changed files with 377 additions and 6 deletions
+169
View File
@@ -21,6 +21,10 @@ beforeEach(() => {
getFlag: vi.fn(() => null),
},
});
vi.stubGlobal('document', {
createElement: vi.fn(tag => ({ tag, srcObject: null, autoplay: false, playsInline: false, muted: false, className: '', addEventListener: vi.fn(), remove: vi.fn() })),
querySelectorAll: vi.fn(() => []),
});
});
afterEach(() => {
@@ -140,6 +144,21 @@ describe('buildParticipantList()', () => {
const list = buildParticipantList(['user-2'], stateStore, controller, adapter);
expect(list[0].stateLabel).toBe('Hidden');
});
it('includes hasStreamAccess flag when passed as true (Story 5.1)', () => {
const list = buildParticipantList(['user-1'], stateStore, controller, adapter, true);
expect(list[0].hasStreamAccess).toBe(true);
});
it('includes hasStreamAccess flag when passed as false (Story 5.1)', () => {
const list = buildParticipantList(['user-1'], stateStore, controller, adapter, false);
expect(list[0].hasStreamAccess).toBe(false);
});
it('defaults hasStreamAccess to false when not provided (Story 5.1)', () => {
const list = buildParticipantList(['user-1'], stateStore, controller, adapter);
expect(list[0].hasStreamAccess).toBe(false);
});
});
describe('ScryingPoolStrip', () => {
@@ -202,5 +221,155 @@ describe('ScryingPoolStrip', () => {
const data = strip.getData();
expect(data.isEmpty).toBe(false);
});
it('returns hasStreamAccess true when webrtc.getMediaStreamForUser is available (Story 5.1)', () => {
adapter.webrtc = {
getMediaStreamForUser: vi.fn(),
};
const data = strip.getData();
expect(data.hasStreamAccess).toBe(true);
});
it('returns hasStreamAccess false when webrtc is null (Story 5.1)', () => {
adapter.webrtc = null;
const data = strip.getData();
expect(data.hasStreamAccess).toBe(false);
});
it('returns hasStreamAccess false when webrtc has no getMediaStreamForUser (Story 5.1)', () => {
adapter.webrtc = {};
const data = strip.getData();
expect(data.hasStreamAccess).toBe(false);
});
});
describe('_attachVideoStream() (Story 5.1)', () => {
let mockVideoContainer;
let consoleWarnSpy;
beforeEach(() => {
consoleWarnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
mockVideoContainer = {
querySelector: vi.fn(),
appendChild: vi.fn(),
};
adapter.webrtc = {
getMediaStreamForUser: vi.fn().mockReturnValue(new MediaStream()),
};
vi.spyOn(document, 'createElement').mockReturnValue({
srcObject: null,
autoplay: false,
playsInline: false,
muted: false,
className: '',
addEventListener: vi.fn(),
});
});
afterEach(() => {
vi.restoreAllMocks();
});
it('creates video element with stream (Story 5.1)', () => {
const participantItem = {
querySelector: vi.fn().mockReturnValue(mockVideoContainer),
};
// Call the method directly
strip._attachVideoStream('user-1', participantItem);
// Check that getMediaStreamForUser was called
expect(adapter.webrtc.getMediaStreamForUser).toHaveBeenCalledWith('user-1');
expect(consoleWarnSpy).not.toHaveBeenCalled();
});
it('returns early and does not warn when webrtc is not available (Story 5.1)', () => {
adapter.webrtc = null;
const participantItem = { querySelector: vi.fn() };
strip._attachVideoStream('user-1', participantItem);
// Should return early without warning since webrtc check happens first
expect(consoleWarnSpy).not.toHaveBeenCalled();
expect(participantItem.querySelector).not.toHaveBeenCalled();
});
it('warns when no video container found (Story 5.1)', () => {
const participantItem = {
querySelector: vi.fn().mockReturnValue(null),
};
strip._attachVideoStream('user-1', participantItem);
expect(consoleWarnSpy).toHaveBeenCalledWith(
'[ScryingPool] No video container found for user:',
'user-1'
);
});
});
describe('_cleanupVideoStreams() (Story 5.1)', () => {
let consoleWarnSpy;
beforeEach(() => {
consoleWarnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
});
afterEach(() => {
vi.restoreAllMocks();
});
it('handles undefined document gracefully', () => {
const originalDocument = global.document;
vi.stubGlobal('document', undefined);
expect(() => strip._cleanupVideoStreams()).not.toThrow();
vi.stubGlobal('document', originalDocument);
});
it('removes video elements and cleans up streams', () => {
const mockStream = new MediaStream();
const mockTrack = { stop: vi.fn() };
const mockVideoElement = {
srcObject: mockStream,
remove: vi.fn(),
};
// Add getTracks method to the mock stream
mockStream.getTracks = vi.fn().mockReturnValue([mockTrack]);
vi.stubGlobal('document', {
querySelectorAll: vi.fn().mockReturnValue([mockVideoElement]),
});
strip._cleanupVideoStreams();
expect(mockStream.getTracks).toHaveBeenCalled();
expect(mockTrack.stop).toHaveBeenCalled();
expect(mockVideoElement.srcObject).toBe(null);
expect(mockVideoElement.remove).toHaveBeenCalled();
});
it('handles video elements without streams gracefully', () => {
const mockVideoElement = {
srcObject: null,
remove: vi.fn(),
};
vi.stubGlobal('document', {
querySelectorAll: vi.fn().mockReturnValue([mockVideoElement]),
});
expect(() => strip._cleanupVideoStreams()).not.toThrow();
expect(mockVideoElement.remove).toHaveBeenCalled();
});
it('handles empty video element list', () => {
vi.stubGlobal('document', {
querySelectorAll: vi.fn().mockReturnValue([]),
});
expect(() => strip._cleanupVideoStreams()).not.toThrow();
});
});
});