testapp: add functionality to delete all rooms and add core tests
This commit is contained in:
parent
be7a37a004
commit
64789951d3
58
.github/workflows/wc-e2e-test.yaml
vendored
58
.github/workflows/wc-e2e-test.yaml
vendored
@ -5,6 +5,64 @@ on:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
|
||||
e2e-test-core:
|
||||
name: E2E Tests Core
|
||||
runs-on: ov-actions-runner
|
||||
steps:
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20'
|
||||
- name: Setup OpenVidu Local Deployment
|
||||
uses: OpenVidu/actions/start-openvidu-local-deployment@main
|
||||
- name: Setup OpenVidu Meet
|
||||
uses: OpenVidu/actions/start-openvidu-meet@main
|
||||
env:
|
||||
MEET_WEBHOOK_ENABLED: true
|
||||
- name: Start testapp
|
||||
shell: bash
|
||||
run: |
|
||||
cd testapp
|
||||
npm run start > ../testapp.log 2>&1 &
|
||||
- name: Wait for testapp to Start
|
||||
shell: bash
|
||||
run: |
|
||||
echo "Waiting for testapp to start on http://localhost:5080..."
|
||||
for i in {1..30}; do
|
||||
if curl -s http://localhost:5080 >/dev/null 2>&1; then
|
||||
echo "Testapp is ready!"
|
||||
exit 0
|
||||
fi
|
||||
echo "Attempt $i/30: Testapp not ready yet, waiting 1 second..."
|
||||
sleep 1
|
||||
done
|
||||
echo "Timeout: Testapp failed to start within 30 seconds"
|
||||
exit 1
|
||||
- name: Run tests
|
||||
run: |
|
||||
cd frontend/webcomponent
|
||||
# Install Playwright browsers
|
||||
mkdir -p /tmp/ms-playwright
|
||||
PLAYWRIGHT_BROWSERS_PATH=/tmp/ms-playwright npx playwright install --with-deps chromium
|
||||
npm run test:e2e-core
|
||||
env:
|
||||
RUN_MODE: CI
|
||||
PLAYWRIGHT_BROWSERS_PATH: /tmp/ms-playwright
|
||||
- name: Upload failed test videos
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: test-videos
|
||||
path: |
|
||||
frontend/webcomponent/test-results/*/*.webm
|
||||
retention-days: 2
|
||||
- name: Clean up
|
||||
if: always()
|
||||
uses: OpenVidu/actions/cleanup@main
|
||||
|
||||
|
||||
|
||||
webcomponent-e2e-test:
|
||||
name: WebComponent E2E Tests
|
||||
runs-on: ov-actions-runner
|
||||
|
||||
278
frontend/webcomponent/tests/e2e/core/room.test.ts
Normal file
278
frontend/webcomponent/tests/e2e/core/room.test.ts
Normal file
@ -0,0 +1,278 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
import * as fs from 'fs';
|
||||
import { PNG } from 'pngjs';
|
||||
import pixelmatch from 'pixelmatch';
|
||||
import {
|
||||
applyVirtualBackground,
|
||||
interactWithElementInIframe,
|
||||
joinRoomAs,
|
||||
leaveRoom,
|
||||
prepareForJoiningRoom,
|
||||
saveScreenshot,
|
||||
startScreenSharing,
|
||||
stopScreenSharing,
|
||||
waitForElementInIframe
|
||||
} from '../../helpers/function-helpers.js';
|
||||
|
||||
let subscribedToAppErrors = false;
|
||||
|
||||
test.describe('Room Functionality Tests', () => {
|
||||
const testAppUrl = 'http://localhost:5080';
|
||||
const testRoomPrefix = 'testing-room';
|
||||
|
||||
// ==========================================
|
||||
// SETUP & TEARDOWN
|
||||
// ==========================================
|
||||
|
||||
test.beforeAll(async ({ browser }) => {
|
||||
// Create a test room before all tests
|
||||
const tempContext = await browser.newContext();
|
||||
const tempPage = await tempContext.newPage();
|
||||
await tempPage.goto(testAppUrl);
|
||||
await tempPage.waitForSelector('.create-room');
|
||||
await tempPage.fill('#room-id-prefix', testRoomPrefix);
|
||||
await tempPage.click('.create-room-btn');
|
||||
await tempPage.waitForSelector(`#${testRoomPrefix}`);
|
||||
await tempPage.close();
|
||||
await tempContext.close();
|
||||
});
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
if (!subscribedToAppErrors) {
|
||||
page.on('console', (msg) => {
|
||||
const type = msg.type();
|
||||
const tag = type === 'error' ? 'ERROR' : type === 'warning' ? 'WARNING' : 'LOG';
|
||||
console.log('[' + tag + ']', msg.text());
|
||||
});
|
||||
subscribedToAppErrors = true;
|
||||
}
|
||||
await prepareForJoiningRoom(page, testAppUrl, testRoomPrefix);
|
||||
});
|
||||
|
||||
test.afterEach(async ({ context }) => {
|
||||
// Save storage state after each test
|
||||
await context.storageState({ path: 'test_localstorage_state.json' });
|
||||
});
|
||||
|
||||
test.afterAll(async ({ browser }) => {
|
||||
// Cleanup: delete the test room
|
||||
const tempContext = await browser.newContext();
|
||||
const tempPage = await tempContext.newPage();
|
||||
await tempPage.goto(testAppUrl);
|
||||
await tempPage.waitForSelector('#delete-all-rooms');
|
||||
await tempPage.click('#delete-all-rooms');
|
||||
await tempPage.close();
|
||||
await tempContext.close();
|
||||
});
|
||||
|
||||
// ==========================================
|
||||
// BASIC FUNCTIONALITY TESTS
|
||||
// ==========================================
|
||||
|
||||
test.describe('Basic Room Features', () => {
|
||||
test('should show the toolbar and media buttons', async ({ page }) => {
|
||||
await joinRoomAs('publisher', page);
|
||||
await waitForElementInIframe(page, '#toolbar');
|
||||
|
||||
// Check media buttons are present
|
||||
await waitForElementInIframe(page, '#camera-btn');
|
||||
await waitForElementInIframe(page, '#mic-btn');
|
||||
|
||||
await leaveRoom(page);
|
||||
});
|
||||
|
||||
test('should start a videoconference and display video elements', async ({ page, browser }) => {
|
||||
// First participant joins
|
||||
await joinRoomAs('publisher', page);
|
||||
await waitForElementInIframe(page, 'ov-session');
|
||||
|
||||
// Check local video element
|
||||
const localVideo = await waitForElementInIframe(page, '.OV_stream.local');
|
||||
await expect(localVideo).toBeVisible();
|
||||
|
||||
// Second participant (moderator) joins
|
||||
const context = await browser.newContext();
|
||||
const moderatorPage = await context.newPage();
|
||||
await prepareForJoiningRoom(moderatorPage, testAppUrl, testRoomPrefix);
|
||||
|
||||
await joinRoomAs('moderator', moderatorPage);
|
||||
await waitForElementInIframe(moderatorPage, 'ov-participant-name-form');
|
||||
|
||||
// Set moderator name
|
||||
await interactWithElementInIframe(moderatorPage, '#participant-name-input', {
|
||||
action: 'fill',
|
||||
value: 'Moderator'
|
||||
});
|
||||
await interactWithElementInIframe(moderatorPage, '#participant-name-submit', { action: 'click' });
|
||||
|
||||
// Verify session established and remote video appears
|
||||
await waitForElementInIframe(moderatorPage, 'ov-session');
|
||||
await waitForElementInIframe(moderatorPage, '.OV_stream.remote');
|
||||
|
||||
// Cleanup
|
||||
await leaveRoom(page);
|
||||
await leaveRoom(moderatorPage);
|
||||
await context.close();
|
||||
});
|
||||
});
|
||||
|
||||
// ==========================================
|
||||
// SCREEN SHARING TESTS
|
||||
// ==========================================
|
||||
|
||||
test.describe('Screen Sharing', () => {
|
||||
test('should be able to share and stop screen sharing', async ({ page }) => {
|
||||
await joinRoomAs('publisher', page);
|
||||
await waitForElementInIframe(page, '#toolbar');
|
||||
|
||||
// Initial state: only camera video
|
||||
let videoCount = await page.frameLocator('iframe').locator('video').count();
|
||||
expect(videoCount).toBe(1);
|
||||
|
||||
// Enable screen share
|
||||
await startScreenSharing(page);
|
||||
videoCount = await page.frameLocator('iframe').locator('video').count();
|
||||
expect(videoCount).toBe(2);
|
||||
|
||||
// Disable screen share
|
||||
await stopScreenSharing(page);
|
||||
videoCount = await page.frameLocator('iframe').locator('video').count();
|
||||
expect(videoCount).toBe(1);
|
||||
|
||||
// Test toggle functionality
|
||||
await startScreenSharing(page);
|
||||
videoCount = await page.frameLocator('iframe').locator('video').count();
|
||||
expect(videoCount).toBe(2);
|
||||
|
||||
await stopScreenSharing(page);
|
||||
videoCount = await page.frameLocator('iframe').locator('video').count();
|
||||
expect(videoCount).toBe(1);
|
||||
|
||||
await leaveRoom(page);
|
||||
});
|
||||
});
|
||||
|
||||
// ==========================================
|
||||
// UI PANELS TESTS
|
||||
// ==========================================
|
||||
|
||||
test.describe('UI Panels and Components', () => {
|
||||
test('should show and interact with chat panel', async ({ page }) => {
|
||||
await joinRoomAs('publisher', page);
|
||||
await waitForElementInIframe(page, 'ov-session');
|
||||
|
||||
// Open chat panel
|
||||
await waitForElementInIframe(page, '#chat-panel-btn');
|
||||
await interactWithElementInIframe(page, '#chat-panel-btn', { action: 'click' });
|
||||
|
||||
// Send a message
|
||||
await waitForElementInIframe(page, '#chat-input');
|
||||
await interactWithElementInIframe(page, '#chat-input', {
|
||||
action: 'fill',
|
||||
value: 'Hello world'
|
||||
});
|
||||
await interactWithElementInIframe(page, '#send-btn', { action: 'click' });
|
||||
|
||||
// Verify message appears
|
||||
const chatMessage = await waitForElementInIframe(page, '.chat-message');
|
||||
await expect(chatMessage).toBeVisible();
|
||||
|
||||
await leaveRoom(page);
|
||||
});
|
||||
|
||||
test('should show activities panel', async ({ page }) => {
|
||||
await joinRoomAs('publisher', page);
|
||||
await waitForElementInIframe(page, 'ov-session');
|
||||
|
||||
// Open activities panel
|
||||
await waitForElementInIframe(page, '#activities-panel-btn');
|
||||
await interactWithElementInIframe(page, '#activities-panel-btn', { action: 'click' });
|
||||
|
||||
// Verify panel is visible
|
||||
const activitiesPanel = await waitForElementInIframe(page, 'ov-activities-panel');
|
||||
await expect(activitiesPanel).toBeVisible();
|
||||
|
||||
await leaveRoom(page);
|
||||
});
|
||||
|
||||
test('should show participants panel', async ({ page }) => {
|
||||
await joinRoomAs('publisher', page);
|
||||
await waitForElementInIframe(page, 'ov-session');
|
||||
|
||||
// Open participants panel
|
||||
await waitForElementInIframe(page, '#participants-panel-btn');
|
||||
await interactWithElementInIframe(page, '#participants-panel-btn', { action: 'click' });
|
||||
|
||||
// Verify panel is visible
|
||||
const participantsPanel = await waitForElementInIframe(page, 'ov-participants-panel');
|
||||
await expect(participantsPanel).toBeVisible();
|
||||
|
||||
await leaveRoom(page);
|
||||
});
|
||||
|
||||
test('should show settings panel', async ({ page }) => {
|
||||
await joinRoomAs('publisher', page);
|
||||
await waitForElementInIframe(page, 'ov-session');
|
||||
|
||||
// Open more options menu
|
||||
await interactWithElementInIframe(page, '#more-options-btn', { action: 'click' });
|
||||
await page.waitForTimeout(500); // Wait for menu animation
|
||||
|
||||
// Open settings panel
|
||||
await interactWithElementInIframe(page, '#toolbar-settings-btn', { action: 'click' });
|
||||
|
||||
// Verify panel is visible
|
||||
const settingsPanel = await waitForElementInIframe(page, 'ov-settings-panel');
|
||||
await expect(settingsPanel).toBeVisible();
|
||||
|
||||
await leaveRoom(page);
|
||||
});
|
||||
});
|
||||
|
||||
// ==========================================
|
||||
// ADVANCED FEATURES TESTS
|
||||
// ==========================================
|
||||
|
||||
test.describe('Advanced Features', () => {
|
||||
test('should apply virtual background and detect visual changes', async ({ page }) => {
|
||||
await joinRoomAs('publisher', page);
|
||||
await waitForElementInIframe(page, 'ov-session');
|
||||
|
||||
// Wait for video element to be ready
|
||||
await waitForElementInIframe(page, '.OV_video-element');
|
||||
|
||||
// Capture baseline screenshot
|
||||
await saveScreenshot(page, 'before.png', '.OV_video-element');
|
||||
|
||||
// Apply virtual background
|
||||
await applyVirtualBackground(page, '2');
|
||||
await page.waitForTimeout(1000); // Allow background processing time
|
||||
|
||||
// Capture post-change screenshot
|
||||
await saveScreenshot(page, 'after.png', '.OV_video-element');
|
||||
|
||||
// Compare images to detect changes
|
||||
const img1 = PNG.sync.read(fs.readFileSync('before.png'));
|
||||
const img2 = PNG.sync.read(fs.readFileSync('after.png'));
|
||||
const { width, height } = img1;
|
||||
const diff = new PNG({ width, height });
|
||||
|
||||
const numDiffPixels = pixelmatch(img1.data, img2.data, diff.data, width, height, {
|
||||
threshold: 0.4
|
||||
});
|
||||
|
||||
// Save diff for debugging purposes
|
||||
fs.writeFileSync('diff.png', PNG.sync.write(diff));
|
||||
|
||||
// Verify significant visual change occurred
|
||||
expect(numDiffPixels).toBeGreaterThan(500);
|
||||
|
||||
// Cleanup test artifacts
|
||||
fs.unlinkSync('before.png');
|
||||
fs.unlinkSync('after.png');
|
||||
fs.unlinkSync('diff.png');
|
||||
|
||||
await leaveRoom(page);
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -1,4 +1,5 @@
|
||||
import { Page, Locator, FrameLocator } from '@playwright/test';
|
||||
import { expect } from '@playwright/test';
|
||||
|
||||
/**
|
||||
* Gets a FrameLocator for an iframe inside a Shadow DOM
|
||||
@ -54,3 +55,86 @@ export async function waitForElementInIframe(
|
||||
|
||||
return elementLocator;
|
||||
}
|
||||
|
||||
// Interacti with an element inside an iframe within Shadow DOM
|
||||
export async function interactWithElementInIframe(
|
||||
page: Page,
|
||||
elementSelector: string,
|
||||
options: {
|
||||
action: 'click' | 'fill' | 'type';
|
||||
value?: string; // Only needed for 'fill' or 'type' actions
|
||||
timeout?: number;
|
||||
} = {
|
||||
action: 'click',
|
||||
value: '',
|
||||
timeout: 30000
|
||||
}
|
||||
): Promise<void> {
|
||||
const { action, value = '', timeout = 30000 } = options;
|
||||
const element = await waitForElementInIframe(page, elementSelector);
|
||||
// Perform the specified action
|
||||
switch (action) {
|
||||
case 'click':
|
||||
await element.click();
|
||||
break;
|
||||
case 'fill':
|
||||
await element.fill(value);
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Unsupported action: ${action}`);
|
||||
}
|
||||
}
|
||||
|
||||
export const prepareForJoiningRoom = async (page: Page, url: string, roomPrefix: string) => {
|
||||
await page.goto(url);
|
||||
await page.waitForSelector('.rooms-container');
|
||||
await page.waitForSelector(`#${roomPrefix}`);
|
||||
await page.click('.dropdown-button');
|
||||
await page.waitForSelector('#join-as-moderator');
|
||||
await page.waitForSelector('#join-as-publisher');
|
||||
};
|
||||
|
||||
export const joinRoomAs = async (role: 'moderator' | 'publisher', page: Page) => {
|
||||
await page.click('#join-as-' + role);
|
||||
const component = page.locator('openvidu-meet');
|
||||
await expect(component).toBeVisible();
|
||||
};
|
||||
|
||||
export const leaveRoom = async (page: Page) => {
|
||||
const button = await waitForElementInIframe(page, '#leave-btn');
|
||||
await button.click();
|
||||
await page.waitForSelector('.event-LEFT');
|
||||
};
|
||||
|
||||
export const startScreenSharing = async (page: Page) => {
|
||||
await interactWithElementInIframe(page, '#screenshare-btn', { action: 'click' });
|
||||
await waitForElementInIframe(page, '#local-element-screen_share', { state: 'visible' });
|
||||
};
|
||||
|
||||
export const stopScreenSharing = async (page: Page) => {
|
||||
await interactWithElementInIframe(page, '#screenshare-btn', { action: 'click' });
|
||||
await page.waitForTimeout(200); // Wait for screen menu
|
||||
await interactWithElementInIframe(page, '#disable-screen-button', { action: 'click' });
|
||||
await page.waitForTimeout(500); // Wait for screen to stop sharing
|
||||
};
|
||||
|
||||
export const applyVirtualBackground = async (page: Page, backgroundId: string) => {
|
||||
await interactWithElementInIframe(page, '#more-options-btn', { action: 'click' });
|
||||
await page.waitForTimeout(500);
|
||||
await interactWithElementInIframe(page, '#virtual-bg-btn', { action: 'click' });
|
||||
await waitForElementInIframe(page, 'ov-background-effects-panel', { state: 'visible' });
|
||||
await interactWithElementInIframe(page, `#effect-${backgroundId}`, { action: 'click' });
|
||||
await interactWithElementInIframe(page, '.panel-close-button', { action: 'click' });
|
||||
};
|
||||
|
||||
export const removeVirtualBackground = async (page: Page) => {
|
||||
await interactWithElementInIframe(page, '#more-options-btn', { action: 'click' });
|
||||
await page.waitForTimeout(500);
|
||||
await interactWithElementInIframe(page, '#virtual-bg-btn', { action: 'click' });
|
||||
await interactWithElementInIframe(page, '#no_effect-btn', { action: 'click' });
|
||||
await page.waitForTimeout(500); // Wait for background to be removed
|
||||
};
|
||||
export const saveScreenshot = async (page: Page, filename: string, selector: string) => {
|
||||
const element = await waitForElementInIframe(page, selector);
|
||||
await element.screenshot({ path: filename });
|
||||
};
|
||||
|
||||
4856
testapp/package-lock.json
generated
4856
testapp/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -21,11 +21,18 @@
|
||||
</div>
|
||||
|
||||
<div class="rooms-list">
|
||||
<div class="mb-3 text-center">
|
||||
<form action="/delete-all-rooms" method="post">
|
||||
<button type="submit" class="btn btn-danger btn-sm" id="delete-all-rooms">
|
||||
Delete All Rooms
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
{{#rooms.length}}
|
||||
<ul class="list-group">
|
||||
{{#rooms}}
|
||||
<li
|
||||
id="{{roomIdPrefix}}"
|
||||
id="{{ roomIdPrefix }}"
|
||||
class="list-group-item d-flex justify-content-between align-items-center"
|
||||
>
|
||||
<span>{{ roomId }}</span>
|
||||
@ -50,13 +57,13 @@
|
||||
name="participantRole"
|
||||
value="moderator"
|
||||
/>
|
||||
<input
|
||||
type="hidden"
|
||||
name="roomId"
|
||||
value="{{ roomId }}"
|
||||
/>
|
||||
<input type="hidden" name="roomId" value="{{ roomId }}" />
|
||||
|
||||
<button type="submit" id="join-as-moderator" class="dropdown-item">
|
||||
<button
|
||||
type="submit"
|
||||
id="join-as-moderator"
|
||||
class="dropdown-item"
|
||||
>
|
||||
Moderator
|
||||
</button>
|
||||
</form>
|
||||
@ -73,13 +80,13 @@
|
||||
name="participantRole"
|
||||
value="publisher"
|
||||
/>
|
||||
<input
|
||||
type="hidden"
|
||||
name="roomId"
|
||||
value="{{ roomId }}"
|
||||
/>
|
||||
<input type="hidden" name="roomId" value="{{ roomId }}" />
|
||||
|
||||
<button type="submit" id="join-as-publisher" class="dropdown-item">
|
||||
<button
|
||||
type="submit"
|
||||
id="join-as-publisher"
|
||||
class="dropdown-item"
|
||||
>
|
||||
Publisher
|
||||
</button>
|
||||
</form>
|
||||
@ -97,13 +104,13 @@
|
||||
name="participantRole"
|
||||
value="publisher"
|
||||
/>
|
||||
<input
|
||||
type="hidden"
|
||||
name="roomId"
|
||||
value="{{ roomId }}"
|
||||
/>
|
||||
<input type="hidden" name="roomId" value="{{ roomId }}" />
|
||||
|
||||
<button type="submit" id="join-as-publisher" class="dropdown-item">
|
||||
<button
|
||||
type="submit"
|
||||
id="join-as-publisher"
|
||||
class="dropdown-item"
|
||||
>
|
||||
View Recordings
|
||||
</button>
|
||||
</form>
|
||||
|
||||
@ -1,5 +1,10 @@
|
||||
import { Request, Response } from 'express';
|
||||
import { getAllRooms, createRoom, deleteRoom } from '../services/roomService';
|
||||
import {
|
||||
getAllRooms,
|
||||
createRoom,
|
||||
deleteRoom,
|
||||
deleteAllRooms,
|
||||
} from '../services/roomService';
|
||||
|
||||
export const getHome = async (req: Request, res: Response) => {
|
||||
try {
|
||||
@ -33,7 +38,7 @@ export const postCreateRoom = async (req: Request, res: Response) => {
|
||||
}
|
||||
};
|
||||
|
||||
export const postDeleteRoom = async (req: Request, res: Response) => {
|
||||
export const deleteRoomCtrl = async (req: Request, res: Response) => {
|
||||
try {
|
||||
const { roomId } = req.body;
|
||||
await deleteRoom(roomId);
|
||||
@ -44,3 +49,21 @@ export const postDeleteRoom = async (req: Request, res: Response) => {
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
export const deleteAllRoomsCtrl = async (_req: Request, res: Response) => {
|
||||
try {
|
||||
const allRooms = await getAllRooms();
|
||||
if (allRooms.rooms.length === 0) {
|
||||
console.log('No rooms to delete');
|
||||
res.render('index', { rooms: [] });
|
||||
return;
|
||||
}
|
||||
const roomIds = allRooms.rooms.map((room) => room.roomId);
|
||||
await deleteAllRooms(roomIds);
|
||||
res.render('index', { rooms: [] });
|
||||
} catch (error) {
|
||||
console.error('Error deleting all rooms:', error);
|
||||
res.status(500).send('Internal Server Error ' + JSON.stringify(error));
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
@ -5,7 +5,8 @@ import path from 'path';
|
||||
import {
|
||||
getHome,
|
||||
postCreateRoom,
|
||||
postDeleteRoom,
|
||||
deleteRoomCtrl,
|
||||
deleteAllRoomsCtrl,
|
||||
} from './controllers/homeController';
|
||||
import { handleWebhook, joinRoom } from './controllers/roomController';
|
||||
import { configService } from './services/configService';
|
||||
@ -31,7 +32,8 @@ app.use(express.json());
|
||||
app.get('/', getHome);
|
||||
app.get('/room', joinRoom);
|
||||
app.post('/room', postCreateRoom);
|
||||
app.post('/room/delete', postDeleteRoom);
|
||||
app.post('/room/delete', deleteRoomCtrl);
|
||||
app.post('/delete-all-rooms', deleteAllRoomsCtrl);
|
||||
app.post('/join-room', joinRoom);
|
||||
app.post('/webhook', (req, res) => {
|
||||
handleWebhook(req, res, io);
|
||||
|
||||
@ -3,9 +3,12 @@ import { configService } from './configService';
|
||||
// @ts-ignore
|
||||
import { MeetRoom, MeetRoomOptions } from '../../../typings/src/room';
|
||||
|
||||
export async function getAllRooms(): Promise<{pagination:any, rooms: MeetRoom[]}> {
|
||||
export async function getAllRooms(): Promise<{
|
||||
pagination: any;
|
||||
rooms: MeetRoom[];
|
||||
}> {
|
||||
const url = `${configService.meetApiUrl}/rooms`;
|
||||
return get<{pagination:any, rooms: MeetRoom[]}>(url, {
|
||||
return get<{ pagination: any; rooms: MeetRoom[] }>(url, {
|
||||
headers: { 'x-api-key': configService.apiKey },
|
||||
});
|
||||
}
|
||||
@ -13,7 +16,8 @@ export async function getAllRooms(): Promise<{pagination:any, rooms: MeetRoom[]}
|
||||
export async function createRoom(roomData: MeetRoomOptions): Promise<MeetRoom> {
|
||||
const url = `${configService.meetApiUrl}/rooms`;
|
||||
// Default to 1 hour if autoDeletionDate is not provided
|
||||
if(!roomData.autoDeletionDate) roomData.autoDeletionDate = new Date(Date.now() + 60 * 61 * 1000).getTime();
|
||||
if (!roomData.autoDeletionDate)
|
||||
roomData.autoDeletionDate = new Date(Date.now() + 60 * 61 * 1000).getTime();
|
||||
console.log('Creating room with options:', roomData);
|
||||
return post<MeetRoom>(url, {
|
||||
headers: { 'x-api-key': configService.apiKey },
|
||||
@ -27,3 +31,11 @@ export async function deleteRoom(roomId: string): Promise<void> {
|
||||
headers: { 'x-api-key': configService.apiKey },
|
||||
});
|
||||
}
|
||||
|
||||
export async function deleteAllRooms(roomIds: string[]): Promise<void> {
|
||||
const url = `${configService.meetApiUrl}/rooms?roomIds=${roomIds.join(',')}`;
|
||||
|
||||
await del<void>(url, {
|
||||
headers: { 'x-api-key': configService.apiKey },
|
||||
});
|
||||
}
|
||||
|
||||
@ -1,42 +1,63 @@
|
||||
export interface RequestOptions {
|
||||
headers?: Record<string, string>;
|
||||
queryParams?: Record<string, string>;
|
||||
body?: any;
|
||||
headers?: Record<string, string>;
|
||||
queryParams?: Record<string, string>;
|
||||
body?: any;
|
||||
}
|
||||
|
||||
async function buildUrl(url: string, queryParams?: Record<string, string>): Promise<string> {
|
||||
if (!queryParams) return url;
|
||||
const params = new URLSearchParams(queryParams as Record<string, string>).toString();
|
||||
return `${url}?${params}`;
|
||||
async function buildUrl(
|
||||
url: string,
|
||||
queryParams?: Record<string, string>
|
||||
): Promise<string> {
|
||||
if (!queryParams) return url;
|
||||
const params = new URLSearchParams(
|
||||
queryParams as Record<string, string>
|
||||
).toString();
|
||||
return `${url}?${params}`;
|
||||
}
|
||||
|
||||
async function request<T>(method: string, url: string, options: RequestOptions = {}): Promise<T> {
|
||||
const fullUrl = await buildUrl(url, options.queryParams);
|
||||
const fetchOptions: RequestInit = {
|
||||
method,
|
||||
headers: { 'Content-Type': 'application/json', ...(options.headers || {}) },
|
||||
body: options.body ? JSON.stringify(options.body) : undefined
|
||||
};
|
||||
const response = await fetch(fullUrl, fetchOptions);
|
||||
if (!response.ok) {
|
||||
const text = await response.text();
|
||||
throw new Error(`HTTP ${response.status}: ${text}`);
|
||||
}
|
||||
return response.json() as Promise<T>;
|
||||
async function request<T>(
|
||||
method: string,
|
||||
url: string,
|
||||
options: RequestOptions = {}
|
||||
): Promise<T> {
|
||||
const fullUrl = await buildUrl(url, options.queryParams);
|
||||
const fetchOptions: RequestInit = {
|
||||
method,
|
||||
headers: { 'Content-Type': 'application/json', ...(options.headers || {}) },
|
||||
body: options.body ? JSON.stringify(options.body) : undefined,
|
||||
};
|
||||
const response = await fetch(fullUrl, fetchOptions);
|
||||
if (!response.ok) {
|
||||
const text = await response.text();
|
||||
throw new Error(`HTTP ${response.status}: ${text}`);
|
||||
}
|
||||
return response.json() as Promise<T>;
|
||||
}
|
||||
|
||||
export function get<T>(url: string, options?: Omit<RequestOptions, 'body'>): Promise<T> {
|
||||
return request<T>('GET', url, options || {});
|
||||
export function get<T>(
|
||||
url: string,
|
||||
options?: Omit<RequestOptions, 'body'>
|
||||
): Promise<T> {
|
||||
return request<T>('GET', url, options || {});
|
||||
}
|
||||
|
||||
export function post<T>(url: string, options?: Omit<RequestOptions, 'body'> & { body: any }): Promise<T> {
|
||||
return request<T>('POST', url, options as RequestOptions);
|
||||
export function post<T>(
|
||||
url: string,
|
||||
options?: Omit<RequestOptions, 'body'> & { body: any }
|
||||
): Promise<T> {
|
||||
return request<T>('POST', url, options as RequestOptions);
|
||||
}
|
||||
|
||||
export function put<T>(url: string, options?: Omit<RequestOptions, 'body'> & { body: any }): Promise<T> {
|
||||
return request<T>('PUT', url, options as RequestOptions);
|
||||
export function put<T>(
|
||||
url: string,
|
||||
options?: Omit<RequestOptions, 'body'> & { body: any }
|
||||
): Promise<T> {
|
||||
return request<T>('PUT', url, options as RequestOptions);
|
||||
}
|
||||
|
||||
export function del<T>(url: string, options?: Omit<RequestOptions, 'body'>): Promise<T> {
|
||||
return request<T>('DELETE', url, options || {});
|
||||
}
|
||||
export function del<T>(
|
||||
url: string,
|
||||
options?: Omit<RequestOptions, 'body'>
|
||||
): Promise<T> {
|
||||
return request<T>('DELETE', url, options || {});
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user