Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
6 changes: 5 additions & 1 deletion .env.template
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ LOCAL_CONTAINER_NAME=""
TIMEOUT_MULTIPLIER= # 1 | 2 | 3
CI="" # "true" | "false"

# Plugin URLs
# Custom plugin URLs
ACTION_BUTTON_DROPDOWN_URL=""
ACTIONS_BAR_URL=""
AUDIO_SETTINGS_DROPDOWN_URL=""
CAMERA_SETTINGS_DROPDOWN_URL=""
CUSTOM_SUBSCRIPTION_HOOK_URL=""
DATA_CHANNEL_URL=""
10 changes: 10 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"[json]": {
"files.insertFinalNewline": true,
"files.trimFinalNewlines": true,
},
"files.associations": {
"package.json": "json",
},
"editor.formatOnSave": true,
}
22 changes: 22 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
"@types/node": "^20.4.4",
"@types/react": "^18.2.15",
"@types/react-dom": "^18.2.7",
"@types/sha.js": "^2.4.4",
"@types/xml2js": "^0.4.14",
"@typescript-eslint/eslint-plugin": "^6.2.0",
"@typescript-eslint/parser": "^6.2.0",
"axios": "^1.8.4",
Expand Down Expand Up @@ -70,4 +72,4 @@
"@browser-bunyan/console-formatted-stream": "^1.8.0",
"browser-bunyan": "^1.8.0"
}
}
}
2 changes: 1 addition & 1 deletion samples/sample-action-button-dropdown-plugin/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,4 +67,4 @@
"webpack-cli": "^5.1.1",
"webpack-dev-server": "^4.15.1"
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ function SampleActionButtonDropdownPlugin(
React.useEffect(() => {
if (currentUser?.presenter) {
pluginApi.setActionButtonDropdownItems([
new ActionButtonDropdownSeparator(),
new ActionButtonDropdownSeparator({
dataTest: 'actionDropdownSeparatorPlugin',
}),
new ActionButtonDropdownOption({
label: 'Button injected by plugin',
icon: 'copy',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@ import { coreElements } from '../../../tests/core/coreElements';

export const elements = {
...coreElements,
pluginSeparator: 'hr[data-test="pluginsSeparator"]',
actionButtonDropdownPluginSeparator: 'hr[data-test="actionDropdownSeparatorPlugin"]',
pluginButton: 'li[data-test="actionDropdownButtonPlugin"]',
};
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ test.describe.parallel('Action button dropdown', () => {
{ timeout: ELEMENT_WAIT_LONGER_TIME },
);
await sampleTest.modPage.page.click(e.actions);
await sampleTest.modPage.hasElement(e.pluginSeparator, 'should display the separator element injected by the plugin');
await sampleTest.modPage.hasElement(e.actionButtonDropdownPluginSeparator, 'should display the action button dropdown separator element injected by the plugin');
await sampleTest.modPage.hasElement(e.pluginButton, 'should display the button element injected by the plugin');
await sampleTest.modPage.hasText(e.pluginButton, 'Button injected by plugin', 'should display the correct text on the injected button');
const [consoleMessage] = await Promise.all([
Expand Down
2 changes: 1 addition & 1 deletion samples/sample-actions-bar-plugin/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,4 @@
"webpack-cli": "^5.1.1",
"webpack-dev-server": "^4.15.1"
}
}
}
2 changes: 1 addition & 1 deletion samples/sample-actions-bar-plugin/tests/test.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { expect } from '@playwright/test';
import { createSampleTest } from '../../../tests/core/fixtures/sampleFixture';
import { checkPluginAvailability } from '../../../tests/core/fixtures/sampleBeforeAll';
import { elements as e } from './elements';
import { extractObject } from './utils/extractObject';
import { extractObject } from '../../../tests/utils/extractObject';

const { test, setPluginUrl, getPluginUrl } = createSampleTest({
envVarName: 'ACTIONS_BAR_URL',
Expand Down
4 changes: 3 additions & 1 deletion samples/sample-audio-settings-dropdown-plugin/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@
},
"scripts": {
"build-bundle": "webpack --mode production",
"start": "webpack serve --mode development"
"start": "webpack serve --mode development",
"test": "npx playwright test -c ../../playwright.config.ts",
"copy-sample-to-container": "../../tests/core/scripts/copy-sample-to-container.sh sample-audio-settings-dropdown-plugin"
},
"browserslist": {
"production": [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ function SampleAudioSettingsDropdownPlugin(
onClick: () => {
pluginLogger.info('Log from audio settings dropdown plugin');
},
dataTest: 'pluginAudioSettingsDropdownButton',
});

const separatorToAudioSettingsDropdown:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { coreElements } from '../../../tests/core/coreElements';

export const elements = {
...coreElements,
pluginAudioSettingsDropdownButton: 'li[data-test="pluginAudioSettingsDropdownButton"]',
};
46 changes: 46 additions & 0 deletions samples/sample-audio-settings-dropdown-plugin/tests/test.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/* eslint-disable import/no-extraneous-dependencies */
import { expect } from '@playwright/test';
import { createSampleTest } from '../../../tests/core/fixtures/sampleFixture';
import { checkPluginAvailability } from '../../../tests/core/fixtures/sampleBeforeAll';
import { elements as e } from './elements';
import { ELEMENT_WAIT_LONGER_TIME } from '../../../tests/core/constants';

const { test, setPluginUrl, getPluginUrl } = createSampleTest({
envVarName: 'AUDIO_SETTINGS_DROPDOWN_URL',
getPluginUrl: () => process.env.AUDIO_SETTINGS_DROPDOWN_URL,
});

test.describe.parallel('Audio Settings Dropdown', () => {
test.beforeAll(checkPluginAvailability({
pluginName: 'sample-audio-settings-dropdown-plugin',
envVarName: 'AUDIO_SETTINGS_DROPDOWN_URL',
setPluginUrl,
getPluginUrl,
}));

test('should display the button with icon and log when clicked', async ({ sampleTest }): Promise<void> => {
await sampleTest.modPage.page.waitForSelector(
e.whiteboard,
{ timeout: ELEMENT_WAIT_LONGER_TIME },
);
await sampleTest.modPage.page.click(e.joinAudioButton);
await sampleTest.modPage.page.click(e.microphoneBtn);
await sampleTest.modPage.page.click(e.joinEchoTestButton);
await sampleTest.modPage.hasElement(e.establishingAudioLabel, 'should display the establishing audio label');
await sampleTest.modPage.wasRemoved(e.establishingAudioLabel, 'should remove the establishing audio label once audio is established');
await sampleTest.modPage.page.click(e.audioDropdownMenu);

const audioSettingsButton = sampleTest.modPage.getLocator(e.pluginAudioSettingsDropdownButton);
await expect.soft(audioSettingsButton, 'should display the audio settings dropdown button injected by the plugin').toBeVisible();
const iconElement = audioSettingsButton.locator('i');
await expect.soft(iconElement, 'should contain correct icon class').toHaveClass(/icon-bbb-user/);
const [consoleMessage] = await Promise.all([
sampleTest.modPage.waitForPluginLogger(),
sampleTest.modPage.page.click(e.pluginAudioSettingsDropdownButton),
]);
expect(
consoleMessage.text(),
'should display the expected log from the plugin button correctly',
).toContain('Log from audio settings dropdown plugin');
});
});
4 changes: 3 additions & 1 deletion samples/sample-camera-settings-dropdown-plugin/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@
},
"scripts": {
"build-bundle": "webpack --mode production",
"start": "webpack serve --mode development"
"start": "webpack serve --mode development",
"test": "npx playwright test -c ../../playwright.config.ts",
"copy-sample-to-container": "../../tests/core/scripts/copy-sample-to-container.sh sample-camera-settings-dropdown-plugin"
},
"browserslist": {
"production": [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ function SampleCameraSettingsDropdownPlugin(
new CameraSettingsDropdownOption({
label: 'This will log on the console',
icon: 'user',
dataTest: 'cameraSettingsDropdownButtonPlugin',
onClick: () => {
pluginLogger.info('Log from camera settings plugin');
},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { coreElements } from '../../../tests/core/coreElements';

export const elements = {
...coreElements,
cameraSettingsDropdownButtonPlugin: 'li[data-test="cameraSettingsDropdownButtonPlugin"]',
};
47 changes: 47 additions & 0 deletions samples/sample-camera-settings-dropdown-plugin/tests/test.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/* eslint-disable import/no-extraneous-dependencies */
import { expect } from '@playwright/test';
import { createSampleTest } from '../../../tests/core/fixtures/sampleFixture';
import { checkPluginAvailability } from '../../../tests/core/fixtures/sampleBeforeAll';
import { elements as e } from './elements';
import { ELEMENT_WAIT_LONGER_TIME } from '../../../tests/core/constants';

const { test, setPluginUrl, getPluginUrl } = createSampleTest({
envVarName: 'CAMERA_SETTINGS_DROPDOWN_URL',
getPluginUrl: () => process.env.CAMERA_SETTINGS_DROPDOWN_URL,
});

test.describe.parallel('Camera Settings Dropdown', () => {
test.beforeAll(checkPluginAvailability({
pluginName: 'sample-camera-settings-dropdown-plugin',
envVarName: 'CAMERA_SETTINGS_DROPDOWN_URL',
setPluginUrl,
getPluginUrl,
}));

test('should display the button with icon and log when clicked', async ({ sampleTest }): Promise<void> => {
await sampleTest.modPage.page.waitForSelector(
e.whiteboard,
{ timeout: ELEMENT_WAIT_LONGER_TIME },
);
await sampleTest.modPage.page.click(e.joinVideoButton);
await sampleTest.modPage.page.click(e.startSharingWebcam);
await sampleTest.modPage.hasElement(e.leaveVideo, 'should display the leave video button after joining video');
await sampleTest.modPage.hasElement('video', 'should display the video element after joining video');
await sampleTest.modPage.page.click(e.videoDropdownMenu);

const cameraSettingsButton = sampleTest.modPage.getLocator(
e.cameraSettingsDropdownButtonPlugin,
);
await expect.soft(cameraSettingsButton, 'should display the camera settings dropdown button injected by the plugin').toBeVisible();
const iconElement = cameraSettingsButton.locator('i');
await expect.soft(iconElement, 'should contain correct icon class').toHaveClass(/icon-bbb-user/);
const [consoleMessage] = await Promise.all([
sampleTest.modPage.waitForPluginLogger(),
sampleTest.modPage.page.click(e.cameraSettingsDropdownButtonPlugin),
]);
expect(
consoleMessage.text(),
'should display the expected log from the plugin button correctly',
).toContain('Log from camera settings plugin');
});
});
4 changes: 3 additions & 1 deletion samples/sample-custom-subscription-hook/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@
},
"scripts": {
"build-bundle": "webpack --mode production",
"start": "webpack serve --mode development"
"start": "webpack serve --mode development",
"test": "npx playwright test -c ../../playwright.config.ts",
"copy-sample-to-container": "../../tests/core/scripts/copy-sample-to-container.sh sample-custom-subscription-hook"
},
"browserslist": {
"production": [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { PresentationFromGraphqlWrapper, SampleCustomSubscriptionPluginProps } f
function SampleCustomPresentationSubscriptionPlugin(
{ pluginUuid: uuid }: SampleCustomSubscriptionPluginProps,
):
React.ReactElement {
React.ReactElement {
BbbPluginSdk.initialize(uuid);
const pluginApi: PluginApi = BbbPluginSdk.getPluginApi(uuid);

Expand Down Expand Up @@ -45,6 +45,7 @@ function SampleCustomPresentationSubscriptionPlugin(
label: 'Log data for next slide',
tooltip: 'It queries data from next slide and logs on the console',
style: {},
dataTest: 'logNextSlideDataButton',
onClick: () => {
pluginLogger.info('Logging data from sample-custom-presentation-subscription-plugin: ', JSON.stringify(dataResult));
},
Expand Down
6 changes: 6 additions & 0 deletions samples/sample-custom-subscription-hook/tests/elements.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { coreElements } from '../../../tests/core/coreElements';

export const elements = {
...coreElements,
logNextSlideDataButton: 'button[data-test="logNextSlideDataButton"]',
};
80 changes: 80 additions & 0 deletions samples/sample-custom-subscription-hook/tests/test.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/* eslint-disable import/no-extraneous-dependencies */
import { expect } from '@playwright/test';
import { createSampleTest } from '../../../tests/core/fixtures/sampleFixture';
import { checkPluginAvailability } from '../../../tests/core/fixtures/sampleBeforeAll';
import { elements as e } from './elements';
import { ELEMENT_WAIT_LONGER_TIME } from '../../../tests/core/constants';
import { extractObject } from '../../../tests/utils/extractObject';

interface NextSlideData {
pres_presentation: {
pages: {
num: number;
urlsJson: {
png: string;
svg: string;
text: string;
};
}[];
}[];
}

const { test, setPluginUrl, getPluginUrl } = createSampleTest({
envVarName: 'CUSTOM_SUBSCRIPTION_HOOK_URL',
getPluginUrl: () => process.env.CUSTOM_SUBSCRIPTION_HOOK_URL,
});

test.describe.parallel('Custom Subscription Hook', () => {
test.beforeAll(checkPluginAvailability({
pluginName: 'sample-custom-subscription-hook',
envVarName: 'CUSTOM_SUBSCRIPTION_HOOK_URL',
setPluginUrl,
getPluginUrl,
}));

test('should display the button with icon and log when clicked', async ({ sampleTest }): Promise<void> => {
await sampleTest.modPage.page.waitForSelector(
e.whiteboard,
{ timeout: ELEMENT_WAIT_LONGER_TIME },
);

await sampleTest.modPage.hasElement(e.presentationToolbarWrapper, 'should display the presentation toolbar element');
const logNextSlideDataButton = sampleTest.modPage.getLocator(e.logNextSlideDataButton);
await expect(logNextSlideDataButton, 'should display the log next slide data button injected by the plugin').toBeVisible();
await expect(logNextSlideDataButton, 'should have the correct text value').toHaveText('Log data for next slide');

const [consoleMessage] = await Promise.all([
sampleTest.modPage.waitForPluginLogger(),
logNextSlideDataButton.click(),
]);

const extractedObject = extractObject<NextSlideData>(consoleMessage.text());
expect(extractedObject, 'should be a valid JavaScript object').toBeTruthy();

const pages = extractedObject?.pres_presentation?.[0]?.pages[0];
const urlsJson = pages?.urlsJson;
expect(pages?.num, 'should log the correct number of second slide').toBe(2);
expect(urlsJson?.png, 'should log the correct PNG URL for the second slide').toBeDefined();
expect(urlsJson?.png, 'PNG URL should be a valid URL').toMatch(/^https?:\/\/.+/);
expect(urlsJson?.svg, 'should log the correct SVG URL for the second slide').toBeDefined();
expect(urlsJson?.svg, 'SVG URL should be a valid URL').toMatch(/^https?:\/\/.+/);
expect(urlsJson?.text, 'should log the correct TEXT URL for the second slide').toBeDefined();
expect(urlsJson?.text, 'TEXT URL should be a valid URL').toMatch(/^https?:\/\/.+/);

const skipSlideSelect = sampleTest.modPage.page.locator(e.skipSlide);
const options = await skipSlideSelect.locator('option').all();
expect(options.length, 'presentation should have more than 1 slide for the plugin to perform as expected').toBeGreaterThan(1);
await skipSlideSelect.selectOption({ index: options.length - 1 });
await expect(sampleTest.modPage.page.locator(e.nextSlide), 'should disable the next slide button when on the last slide').toBeDisabled();

const [consoleMessage2] = await Promise.all([
sampleTest.modPage.waitForPluginLogger(),
logNextSlideDataButton.click(),
]);

const extractedObject2 = extractObject<NextSlideData>(consoleMessage2.text());
expect(extractedObject2, 'should be a valid JavaScript object').toBeTruthy();
const pages2 = extractedObject2?.pres_presentation?.[0]?.pages;
expect(pages2, 'should not log any data of next slide when on the last slide').toEqual([]);
});
});
4 changes: 3 additions & 1 deletion samples/sample-data-channel-plugin/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@
},
"scripts": {
"build-bundle": "webpack --mode production",
"start": "webpack serve --mode development"
"start": "webpack serve --mode development",
"test": "npx playwright test -c ../../playwright.config.ts",
"copy-sample-to-container": "../../tests/core/scripts/copy-sample-to-container.sh sample-data-channel-plugin"
},
"browserslist": {
"production": [
Expand Down
Loading