snapshot of https://github.com/mattermost/mattermost.git (master, 2026-09-16; blobs > 131072B omitted)
Some checks failed
Server CI / Postgres (shard 0) (push) Has been skipped
Server CI / Postgres (shard 3) (push) Has been skipped
BuildEnv Docker Image / build-image (push) Failing after 4s
BuildEnv Docker Image / build-image-fips (push) Failing after 4s
Migration Review & Release Notes / Generate migration review & release notes (push) Failing after 3s
Server CI / Build Environment (push) Failing after 3s
Server CI / Postgres (shard 1) (push) Has been skipped
Tools CI / check-style (mattermost-govet) (push) Failing after 4s
Server CI / Postgres (shard 2) (push) Has been skipped
Tools CI / check-style (mmgotool) (push) Failing after 3s
Server CI / Elasticsearch v8 Compatibility (push) Has been skipped
Server CI / OpenSearch v2 Compatibility (push) Has been skipped
Server CI / Postgres FIPS (shard 0) (push) Has been skipped
Tools CI / Test (mattermost-govet) (push) Failing after 3s
Server CI / Postgres FIPS (shard 1) (push) Has been skipped
Server CI / Postgres FIPS (shard 2) (push) Has been skipped
Tools CI / Test (mmgotool) (push) Failing after 3s
Server CI / Postgres FIPS (shard 3) (push) Has been skipped
Server CI / Run mmctl tests (push) Has been skipped
Server CI / Run mmctl tests (FIPS) (push) Has been skipped
Server CI / Merge Postgres Test Results (push) Has been skipped
Server CI / Merge Postgres FIPS Test Results (push) Has been skipped
Server CI / Check backport migrations (push) Has been skipped
Server CI / Check generated files (push) Has been skipped
Server CI / check-style (push) Has been skipped
Server CI / Vet API (push) Has been skipped
Server CI / Build mattermost server app (push) Has been skipped
Server CI / Server CI Complete (push) Failing after 2s
Server CI / Server CI Artifacts (push) Has been skipped
Server CI / Sentry Upload (push) Has been skipped
Server CI / Server CI Report (push) Failing after 5m1s
Server CI Nightly Race / Race Detector (push) Has been skipped
CodeQL / Analyze (go) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
Webapp CI Cache Warm / Warm Webapp node_modules Cache (push) Has been cancelled
E2E CI Cache Warm / Warm E2E npm Registry Cache (push) Has been cancelled
API / build (push) Has been cancelled
Web App CI / check-types (push) Has been cancelled
Web App CI / check-lint (push) Has been cancelled
Web App CI / check-i18n (push) Has been cancelled
Web App CI / check-external-links (push) Has been cancelled
Web App CI / test (platform) (push) Has been cancelled
Web App CI / test (mattermost-redux) (push) Has been cancelled
Web App CI / test (channels shard 1/4) (push) Has been cancelled
Web App CI / test (channels shard 2/4) (push) Has been cancelled
Web App CI / test (channels shard 3/4) (push) Has been cancelled
Web App CI / test (channels shard 4/4) (push) Has been cancelled
Web App CI / upload-coverage (push) Has been cancelled
Web App CI / build (push) Has been cancelled
YAML Lint / yamllint (push) Has been cancelled
Push mirrored docker images / cd/Push mirrored docker images (push) Has been cancelled
docs-cd / Build and deploy docs (push) Has been cancelled
Docs CI / build (push) Has been cancelled
E2E Cache Warm: Cypress deps / Warm Cypress deps cache (push) Has been cancelled
Scorecards supply-chain security / Scorecard analysis (push) Has been cancelled
Server CI Weekly / Postgres FIPS (push) Has been skipped
Server CI Weekly / Run mmctl tests (FIPS) (push) Has been skipped
Server CI Weekly / Postgres with binary parameters (push) Has been skipped
Server CI Weekly / Build Environment (push) Failing after 1s
Server CI Nightly Race / Build Environment (push) Failing after 1s
Server CI Cache Warm / Warm Go Module and Build Cache (push) Failing after 1s
Some checks failed
Server CI / Postgres (shard 0) (push) Has been skipped
Server CI / Postgres (shard 3) (push) Has been skipped
BuildEnv Docker Image / build-image (push) Failing after 4s
BuildEnv Docker Image / build-image-fips (push) Failing after 4s
Migration Review & Release Notes / Generate migration review & release notes (push) Failing after 3s
Server CI / Build Environment (push) Failing after 3s
Server CI / Postgres (shard 1) (push) Has been skipped
Tools CI / check-style (mattermost-govet) (push) Failing after 4s
Server CI / Postgres (shard 2) (push) Has been skipped
Tools CI / check-style (mmgotool) (push) Failing after 3s
Server CI / Elasticsearch v8 Compatibility (push) Has been skipped
Server CI / OpenSearch v2 Compatibility (push) Has been skipped
Server CI / Postgres FIPS (shard 0) (push) Has been skipped
Tools CI / Test (mattermost-govet) (push) Failing after 3s
Server CI / Postgres FIPS (shard 1) (push) Has been skipped
Server CI / Postgres FIPS (shard 2) (push) Has been skipped
Tools CI / Test (mmgotool) (push) Failing after 3s
Server CI / Postgres FIPS (shard 3) (push) Has been skipped
Server CI / Run mmctl tests (push) Has been skipped
Server CI / Run mmctl tests (FIPS) (push) Has been skipped
Server CI / Merge Postgres Test Results (push) Has been skipped
Server CI / Merge Postgres FIPS Test Results (push) Has been skipped
Server CI / Check backport migrations (push) Has been skipped
Server CI / Check generated files (push) Has been skipped
Server CI / check-style (push) Has been skipped
Server CI / Vet API (push) Has been skipped
Server CI / Build mattermost server app (push) Has been skipped
Server CI / Server CI Complete (push) Failing after 2s
Server CI / Server CI Artifacts (push) Has been skipped
Server CI / Sentry Upload (push) Has been skipped
Server CI / Server CI Report (push) Failing after 5m1s
Server CI Nightly Race / Race Detector (push) Has been skipped
CodeQL / Analyze (go) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
Webapp CI Cache Warm / Warm Webapp node_modules Cache (push) Has been cancelled
E2E CI Cache Warm / Warm E2E npm Registry Cache (push) Has been cancelled
API / build (push) Has been cancelled
Web App CI / check-types (push) Has been cancelled
Web App CI / check-lint (push) Has been cancelled
Web App CI / check-i18n (push) Has been cancelled
Web App CI / check-external-links (push) Has been cancelled
Web App CI / test (platform) (push) Has been cancelled
Web App CI / test (mattermost-redux) (push) Has been cancelled
Web App CI / test (channels shard 1/4) (push) Has been cancelled
Web App CI / test (channels shard 2/4) (push) Has been cancelled
Web App CI / test (channels shard 3/4) (push) Has been cancelled
Web App CI / test (channels shard 4/4) (push) Has been cancelled
Web App CI / upload-coverage (push) Has been cancelled
Web App CI / build (push) Has been cancelled
YAML Lint / yamllint (push) Has been cancelled
Push mirrored docker images / cd/Push mirrored docker images (push) Has been cancelled
docs-cd / Build and deploy docs (push) Has been cancelled
Docs CI / build (push) Has been cancelled
E2E Cache Warm: Cypress deps / Warm Cypress deps cache (push) Has been cancelled
Scorecards supply-chain security / Scorecard analysis (push) Has been cancelled
Server CI Weekly / Postgres FIPS (push) Has been skipped
Server CI Weekly / Run mmctl tests (FIPS) (push) Has been skipped
Server CI Weekly / Postgres with binary parameters (push) Has been skipped
Server CI Weekly / Build Environment (push) Failing after 1s
Server CI Nightly Race / Build Environment (push) Failing after 1s
Server CI Cache Warm / Warm Go Module and Build Cache (push) Failing after 1s
This commit is contained in:
@@ -0,0 +1,563 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import type {AdminConfig} from '@mattermost/types/config';
|
||||
|
||||
import {expect, test} from '@mattermost/playwright-lib';
|
||||
|
||||
/**
|
||||
* Patch the Posts page required fields to known valid values so tests that
|
||||
* load the page always start with a saveable form state, regardless of what
|
||||
* other parallel tests may have left in the server config.
|
||||
*/
|
||||
async function resetPostsConfig(adminClient: {patchConfig: (config: Partial<AdminConfig>) => Promise<unknown>}) {
|
||||
await adminClient.patchConfig({
|
||||
ServiceSettings: {
|
||||
PersistentNotificationIntervalMinutes: 5,
|
||||
PersistentNotificationMaxRecipients: 5,
|
||||
PersistentNotificationMaxCount: 6,
|
||||
},
|
||||
} as Partial<AdminConfig>);
|
||||
}
|
||||
|
||||
test.describe('System Console > Self-Deleting Messages', () => {
|
||||
test('admin can enable and disable self-deleting messages', async ({pw}) => {
|
||||
const {adminUser, adminClient} = await pw.initSetup();
|
||||
|
||||
const license = await adminClient.getClientLicenseOld();
|
||||
test.skip(
|
||||
license.SkuShortName !== 'advanced' && license.short_sku_name !== 'advanced',
|
||||
'Skipping test - server does not have enterprise advanced license',
|
||||
);
|
||||
|
||||
if (!adminUser) {
|
||||
throw new Error('Failed to create admin user');
|
||||
}
|
||||
|
||||
// # Reset Posts section required fields so Save button is always enabled
|
||||
await resetPostsConfig(adminClient);
|
||||
|
||||
// # Log in as admin
|
||||
const {systemConsolePage, page} = await pw.testBrowser.login(adminUser);
|
||||
|
||||
// # Visit system console
|
||||
await systemConsolePage.goto();
|
||||
await systemConsolePage.toBeVisible();
|
||||
|
||||
// # Navigate to Posts section
|
||||
await systemConsolePage.sidebar.siteConfiguration.posts.click();
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
// * Verify Posts section is visible
|
||||
const postsSection = page.getByTestId('sysconsole_section_PostSettings');
|
||||
await expect(postsSection).toBeVisible();
|
||||
|
||||
// Get BoR setting elements
|
||||
const enableToggleTrue = postsSection.getByTestId('ServiceSettings.EnableBurnOnReadtrue');
|
||||
const enableToggleFalse = postsSection.getByTestId('ServiceSettings.EnableBurnOnReadfalse');
|
||||
const durationDropdown = postsSection.getByTestId('ServiceSettings.BurnOnReadDurationSecondsdropdown');
|
||||
const maxTTLDropdown = postsSection.getByTestId('ServiceSettings.BurnOnReadMaximumTimeToLiveSecondsdropdown');
|
||||
const saveButton = postsSection.getByRole('button', {name: 'Save'});
|
||||
|
||||
// # If feature is enabled, disable it first
|
||||
if (await enableToggleTrue.isChecked()) {
|
||||
await enableToggleFalse.click();
|
||||
await saveButton.click();
|
||||
await pw.waitUntil(async () => (await saveButton.textContent()) === 'Save');
|
||||
}
|
||||
|
||||
// * Verify dropdowns are disabled when feature is off
|
||||
expect(await durationDropdown.isDisabled()).toBe(true);
|
||||
expect(await maxTTLDropdown.isDisabled()).toBe(true);
|
||||
|
||||
// # Enable the feature
|
||||
await enableToggleTrue.click();
|
||||
|
||||
// * Verify feature is enabled
|
||||
expect(await enableToggleTrue.isChecked()).toBe(true);
|
||||
|
||||
// * Verify dropdowns are now enabled
|
||||
expect(await durationDropdown.isDisabled()).toBe(false);
|
||||
expect(await maxTTLDropdown.isDisabled()).toBe(false);
|
||||
|
||||
// # Save settings
|
||||
await saveButton.click();
|
||||
await pw.waitUntil(async () => (await saveButton.textContent()) === 'Save');
|
||||
|
||||
// # Navigate away and back to verify persistence
|
||||
await systemConsolePage.sidebar.userManagement.users.click();
|
||||
await systemConsolePage.users.toBeVisible();
|
||||
await systemConsolePage.sidebar.siteConfiguration.posts.click();
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
// * Verify feature is still enabled
|
||||
expect(await enableToggleTrue.isChecked()).toBe(true);
|
||||
});
|
||||
|
||||
test('admin can configure message duration', async ({pw}) => {
|
||||
const {adminUser, adminClient} = await pw.initSetup();
|
||||
|
||||
const license = await adminClient.getClientLicenseOld();
|
||||
test.skip(
|
||||
license.SkuShortName !== 'advanced' && license.short_sku_name !== 'advanced',
|
||||
'Skipping test - server does not have enterprise advanced license',
|
||||
);
|
||||
|
||||
if (!adminUser) {
|
||||
throw new Error('Failed to create admin user');
|
||||
}
|
||||
|
||||
// # Reset Posts section required fields so Save button is always enabled
|
||||
await resetPostsConfig(adminClient);
|
||||
|
||||
// # Ensure BoR is enabled via API
|
||||
const config = await adminClient.getConfig();
|
||||
config.ServiceSettings.EnableBurnOnRead = true;
|
||||
await adminClient.patchConfig(config);
|
||||
|
||||
// # Log in as admin
|
||||
const {systemConsolePage, page} = await pw.testBrowser.login(adminUser);
|
||||
|
||||
// # Visit system console
|
||||
await systemConsolePage.goto();
|
||||
await systemConsolePage.toBeVisible();
|
||||
|
||||
// # Navigate to Posts section
|
||||
await systemConsolePage.sidebar.siteConfiguration.posts.click();
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
const postsSection = page.getByTestId('sysconsole_section_PostSettings');
|
||||
const durationDropdown = postsSection.getByTestId('ServiceSettings.BurnOnReadDurationSecondsdropdown');
|
||||
const saveButton = postsSection.getByRole('button', {name: 'Save'});
|
||||
|
||||
// # Select 60 seconds duration
|
||||
await durationDropdown.selectOption('60');
|
||||
|
||||
// # Save settings
|
||||
await saveButton.click();
|
||||
await pw.waitUntil(async () => (await saveButton.textContent()) === 'Save');
|
||||
|
||||
// # Navigate away and back
|
||||
await systemConsolePage.sidebar.userManagement.users.click();
|
||||
await systemConsolePage.users.toBeVisible();
|
||||
await systemConsolePage.sidebar.siteConfiguration.posts.click();
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
// * Verify duration is still 60 seconds
|
||||
expect(await durationDropdown.inputValue()).toBe('60');
|
||||
});
|
||||
|
||||
test('admin can configure maximum time to live', async ({pw}) => {
|
||||
const {adminUser, adminClient} = await pw.initSetup();
|
||||
|
||||
const license = await adminClient.getClientLicenseOld();
|
||||
test.skip(
|
||||
license.SkuShortName !== 'advanced' && license.short_sku_name !== 'advanced',
|
||||
'Skipping test - server does not have enterprise advanced license',
|
||||
);
|
||||
|
||||
if (!adminUser) {
|
||||
throw new Error('Failed to create admin user');
|
||||
}
|
||||
|
||||
// # Reset Posts section required fields so Save button is always enabled
|
||||
await resetPostsConfig(adminClient);
|
||||
|
||||
// # Ensure BoR is enabled via API
|
||||
const config = await adminClient.getConfig();
|
||||
config.ServiceSettings.EnableBurnOnRead = true;
|
||||
await adminClient.patchConfig(config);
|
||||
|
||||
// # Log in as admin
|
||||
const {systemConsolePage, page} = await pw.testBrowser.login(adminUser);
|
||||
|
||||
// # Visit system console
|
||||
await systemConsolePage.goto();
|
||||
await systemConsolePage.toBeVisible();
|
||||
|
||||
// # Navigate to Posts section
|
||||
await systemConsolePage.sidebar.siteConfiguration.posts.click();
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
const postsSection = page.getByTestId('sysconsole_section_PostSettings');
|
||||
const maxTTLDropdown = postsSection.getByTestId('ServiceSettings.BurnOnReadMaximumTimeToLiveSecondsdropdown');
|
||||
const saveButton = postsSection.getByRole('button', {name: 'Save'});
|
||||
|
||||
// # Select 1 day (86400 seconds) max TTL
|
||||
await maxTTLDropdown.selectOption('86400');
|
||||
|
||||
// # Save settings
|
||||
await saveButton.click();
|
||||
await pw.waitUntil(async () => (await saveButton.textContent()) === 'Save');
|
||||
|
||||
// # Navigate away and back
|
||||
await systemConsolePage.sidebar.userManagement.users.click();
|
||||
await systemConsolePage.users.toBeVisible();
|
||||
await systemConsolePage.sidebar.siteConfiguration.posts.click();
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
// * Verify max TTL is still 1 day
|
||||
expect(await maxTTLDropdown.inputValue()).toBe('86400');
|
||||
});
|
||||
|
||||
test('dropdowns are disabled when feature is disabled', async ({pw}) => {
|
||||
const {adminUser, adminClient} = await pw.initSetup();
|
||||
|
||||
const license = await adminClient.getClientLicenseOld();
|
||||
test.skip(
|
||||
license.SkuShortName !== 'advanced' && license.short_sku_name !== 'advanced',
|
||||
'Skipping test - server does not have enterprise advanced license',
|
||||
);
|
||||
|
||||
if (!adminUser) {
|
||||
throw new Error('Failed to create admin user');
|
||||
}
|
||||
|
||||
// # Disable BoR via API to start with a known state
|
||||
const config = await adminClient.getConfig();
|
||||
config.ServiceSettings.EnableBurnOnRead = false;
|
||||
await adminClient.patchConfig(config);
|
||||
await pw.waitUntil(async () => {
|
||||
const cfg = await adminClient.getConfig();
|
||||
return cfg.ServiceSettings?.EnableBurnOnRead === false;
|
||||
});
|
||||
|
||||
// # Log in as admin
|
||||
const {systemConsolePage, page} = await pw.testBrowser.login(adminUser);
|
||||
|
||||
// # Visit system console
|
||||
await systemConsolePage.goto();
|
||||
await systemConsolePage.toBeVisible();
|
||||
|
||||
// # Navigate to Posts section
|
||||
await systemConsolePage.sidebar.siteConfiguration.posts.click();
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
const postsSection = page.getByTestId('sysconsole_section_PostSettings');
|
||||
const enableToggleTrue = postsSection.getByTestId('ServiceSettings.EnableBurnOnReadtrue');
|
||||
const enableToggleFalse = postsSection.getByTestId('ServiceSettings.EnableBurnOnReadfalse');
|
||||
const durationDropdown = postsSection.getByTestId('ServiceSettings.BurnOnReadDurationSecondsdropdown');
|
||||
const maxTTLDropdown = postsSection.getByTestId('ServiceSettings.BurnOnReadMaximumTimeToLiveSecondsdropdown');
|
||||
|
||||
// * Verify feature is disabled (from API config) — use built-in retry to tolerate render lag
|
||||
await expect(enableToggleFalse).toBeChecked({timeout: 10000});
|
||||
|
||||
// * Verify dropdowns are disabled when feature is off
|
||||
await expect(durationDropdown).toBeDisabled({timeout: 30000});
|
||||
await expect(maxTTLDropdown).toBeDisabled({timeout: 30000});
|
||||
|
||||
// # Enable the feature (just toggle, don't save)
|
||||
await enableToggleTrue.click();
|
||||
|
||||
// * Verify dropdowns are now enabled
|
||||
await expect(durationDropdown).not.toBeDisabled({timeout: 30000});
|
||||
await expect(maxTTLDropdown).not.toBeDisabled({timeout: 30000});
|
||||
|
||||
// # Toggle back to disabled
|
||||
await enableToggleFalse.click();
|
||||
|
||||
// * Verify dropdowns are disabled again
|
||||
await expect(durationDropdown).toBeDisabled({timeout: 30000});
|
||||
await expect(maxTTLDropdown).toBeDisabled({timeout: 30000});
|
||||
});
|
||||
|
||||
test('settings persist after page reload', async ({pw}) => {
|
||||
const {adminUser, adminClient} = await pw.initSetup();
|
||||
|
||||
const license = await adminClient.getClientLicenseOld();
|
||||
test.skip(
|
||||
license.SkuShortName !== 'advanced' && license.short_sku_name !== 'advanced',
|
||||
'Skipping test - server does not have enterprise advanced license',
|
||||
);
|
||||
|
||||
if (!adminUser) {
|
||||
throw new Error('Failed to create admin user');
|
||||
}
|
||||
|
||||
// # Configure BoR via API with specific values (using valid dropdown options)
|
||||
// Duration: 300 (5 minutes), Max TTL: 259200 (3 days)
|
||||
await adminClient.patchConfig({
|
||||
ServiceSettings: {
|
||||
EnableBurnOnRead: true,
|
||||
BurnOnReadDurationSeconds: 300,
|
||||
BurnOnReadMaximumTimeToLiveSeconds: 259200,
|
||||
},
|
||||
});
|
||||
// Wait until the server confirms the patch before logging in, so the browser
|
||||
// reads the correct value when it loads the Posts section. A concurrent
|
||||
// initSetup() reset may otherwise overwrite BurnOnReadDurationSeconds.
|
||||
await pw.waitUntil(async () => {
|
||||
const cfg = await adminClient.getConfig();
|
||||
return cfg.ServiceSettings.BurnOnReadDurationSeconds === 300;
|
||||
});
|
||||
|
||||
// # Log in as admin
|
||||
const {systemConsolePage, page} = await pw.testBrowser.login(adminUser);
|
||||
|
||||
// # Visit system console
|
||||
await systemConsolePage.goto();
|
||||
await systemConsolePage.toBeVisible();
|
||||
|
||||
// # Navigate to Posts section
|
||||
await systemConsolePage.sidebar.siteConfiguration.posts.click();
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
const postsSection = page.getByTestId('sysconsole_section_PostSettings');
|
||||
const enableToggleTrue = postsSection.getByTestId('ServiceSettings.EnableBurnOnReadtrue');
|
||||
const durationDropdown = postsSection.getByTestId('ServiceSettings.BurnOnReadDurationSecondsdropdown');
|
||||
const maxTTLDropdown = postsSection.getByTestId('ServiceSettings.BurnOnReadMaximumTimeToLiveSecondsdropdown');
|
||||
|
||||
// * Verify configured values are displayed
|
||||
expect(await enableToggleTrue.isChecked()).toBe(true);
|
||||
expect(await durationDropdown.inputValue()).toBe('300');
|
||||
expect(await maxTTLDropdown.inputValue()).toBe('259200');
|
||||
|
||||
// Re-apply guard: a concurrent initSetup() may reset BoR config between
|
||||
// the initial page load and this reload.
|
||||
await adminClient.patchConfig({
|
||||
ServiceSettings: {
|
||||
BurnOnReadDurationSeconds: 300,
|
||||
BurnOnReadMaximumTimeToLiveSeconds: 259200,
|
||||
},
|
||||
});
|
||||
await pw.waitUntil(async () => {
|
||||
const cfg = await adminClient.getConfig();
|
||||
return cfg.ServiceSettings.BurnOnReadDurationSeconds === 300;
|
||||
});
|
||||
|
||||
// # Reload directly to Posts section
|
||||
await page.goto('/admin_console/site_config/posts');
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
// * Verify values persist after reload — toHaveValue has built-in retry
|
||||
await expect(enableToggleTrue).toBeChecked({timeout: 5000});
|
||||
await expect(durationDropdown).toHaveValue('300', {timeout: 5000});
|
||||
await expect(maxTTLDropdown).toHaveValue('259200', {timeout: 5000});
|
||||
});
|
||||
|
||||
test('BoR toggle appears in channels when feature is enabled in System Console', async ({pw}) => {
|
||||
const {adminUser, adminClient, team} = await pw.initSetup();
|
||||
|
||||
const license = await adminClient.getClientLicenseOld();
|
||||
test.skip(
|
||||
license.SkuShortName !== 'advanced' && license.short_sku_name !== 'advanced',
|
||||
'Skipping test - server does not have enterprise advanced license',
|
||||
);
|
||||
|
||||
if (!adminUser) {
|
||||
throw new Error('Failed to create admin user');
|
||||
}
|
||||
|
||||
// # Reset Posts section required fields so Save button is always enabled
|
||||
await resetPostsConfig(adminClient);
|
||||
|
||||
// # First, disable BoR via API to start clean
|
||||
const config = await adminClient.getConfig();
|
||||
config.ServiceSettings.EnableBurnOnRead = false;
|
||||
await adminClient.patchConfig(config);
|
||||
|
||||
// # Log in as admin
|
||||
const {systemConsolePage, page} = await pw.testBrowser.login(adminUser);
|
||||
|
||||
// # Visit system console
|
||||
await systemConsolePage.goto();
|
||||
await systemConsolePage.toBeVisible();
|
||||
|
||||
// # Navigate to Posts section
|
||||
await systemConsolePage.sidebar.siteConfiguration.posts.click();
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
const postsSection = page.getByTestId('sysconsole_section_PostSettings');
|
||||
const enableToggleTrue = postsSection.getByTestId('ServiceSettings.EnableBurnOnReadtrue');
|
||||
const saveButton = postsSection.getByRole('button', {name: 'Save'});
|
||||
|
||||
// # Enable BoR feature
|
||||
await enableToggleTrue.click();
|
||||
await saveButton.click();
|
||||
await pw.waitUntil(async () => (await saveButton.textContent()) === 'Save');
|
||||
|
||||
// Re-apply guard: concurrent initSetup() may reset EnableBurnOnRead between UI save and navigation
|
||||
await adminClient.patchConfig({ServiceSettings: {EnableBurnOnRead: true}});
|
||||
await pw.waitUntil(async () => {
|
||||
const cfg = await adminClient.getConfig();
|
||||
return cfg.ServiceSettings.EnableBurnOnRead === true;
|
||||
});
|
||||
|
||||
// # Navigate to Channels by going to the team URL
|
||||
await page.goto(`/${team.name}/channels/off-topic`);
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
// * Verify BoR toggle is visible in post create area
|
||||
const borButton = page.getByRole('button', {name: /Burn-on-read/i});
|
||||
await expect(borButton).toBeVisible({timeout: 10000});
|
||||
});
|
||||
|
||||
test('BoR toggle is hidden when feature is disabled in System Console', async ({pw}) => {
|
||||
const {adminUser, adminClient, team} = await pw.initSetup();
|
||||
|
||||
const license = await adminClient.getClientLicenseOld();
|
||||
test.skip(
|
||||
license.SkuShortName !== 'advanced' && license.short_sku_name !== 'advanced',
|
||||
'Skipping test - server does not have enterprise advanced license',
|
||||
);
|
||||
|
||||
if (!adminUser) {
|
||||
throw new Error('Failed to create admin user');
|
||||
}
|
||||
|
||||
// # Reset Posts section required fields so Save button is always enabled
|
||||
await resetPostsConfig(adminClient);
|
||||
|
||||
// # First, enable BoR via API
|
||||
const config = await adminClient.getConfig();
|
||||
config.ServiceSettings.EnableBurnOnRead = true;
|
||||
await adminClient.patchConfig(config);
|
||||
|
||||
// # Log in as admin
|
||||
const {systemConsolePage, page} = await pw.testBrowser.login(adminUser);
|
||||
|
||||
// # Visit system console
|
||||
await systemConsolePage.goto();
|
||||
await systemConsolePage.toBeVisible();
|
||||
|
||||
// # Navigate to Posts section
|
||||
await systemConsolePage.sidebar.siteConfiguration.posts.click();
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
const postsSection = page.getByTestId('sysconsole_section_PostSettings');
|
||||
const enableToggleFalse = postsSection.getByTestId('ServiceSettings.EnableBurnOnReadfalse');
|
||||
const saveButton = postsSection.getByRole('button', {name: 'Save'});
|
||||
|
||||
// # Disable BoR feature
|
||||
await enableToggleFalse.click();
|
||||
await saveButton.click();
|
||||
await pw.waitUntil(async () => (await saveButton.textContent()) === 'Save');
|
||||
|
||||
// Re-apply guard: concurrent initSetup() may re-enable BoR between UI save and navigation
|
||||
await adminClient.patchConfig({ServiceSettings: {EnableBurnOnRead: false}});
|
||||
await pw.waitUntil(async () => {
|
||||
const cfg = await adminClient.getConfig();
|
||||
return cfg.ServiceSettings.EnableBurnOnRead === false;
|
||||
});
|
||||
|
||||
// # Navigate to Channels by going to the team URL
|
||||
await page.goto(`/${team.name}/channels/off-topic`);
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
// * Verify BoR toggle is NOT visible in post create area
|
||||
const borButton = page.getByRole('button', {name: /Burn-on-read/i});
|
||||
await expect(borButton).not.toBeVisible({timeout: 5000});
|
||||
});
|
||||
|
||||
test('configured duration affects timer countdown in channels', async ({pw}) => {
|
||||
const {adminUser, adminClient, team} = await pw.initSetup();
|
||||
|
||||
const license = await adminClient.getClientLicenseOld();
|
||||
test.skip(
|
||||
license.SkuShortName !== 'advanced' && license.short_sku_name !== 'advanced',
|
||||
'Skipping test - server does not have enterprise advanced license',
|
||||
);
|
||||
|
||||
if (!adminUser) {
|
||||
throw new Error('Failed to create admin user');
|
||||
}
|
||||
|
||||
// # Configure BoR with 5 minute (300 seconds) duration
|
||||
const config = await adminClient.getConfig();
|
||||
config.ServiceSettings.EnableBurnOnRead = true;
|
||||
config.ServiceSettings.BurnOnReadDurationSeconds = 300; // 5 minutes
|
||||
config.ServiceSettings.BurnOnReadMaximumTimeToLiveSeconds = 604800; // 7 days (so max TTL doesn't interfere)
|
||||
await adminClient.patchConfig(config);
|
||||
|
||||
// # Verify the config was applied before proceeding (guard against state pollution)
|
||||
await pw.waitUntil(async () => {
|
||||
const cfg = await adminClient.getConfig();
|
||||
return cfg.ServiceSettings.BurnOnReadDurationSeconds === 300;
|
||||
});
|
||||
|
||||
// # Create a second user to receive the message
|
||||
const randomUser = await pw.random.user();
|
||||
const receiver = await adminClient.createUser(randomUser, '', '');
|
||||
(receiver as any).password = randomUser.password;
|
||||
await adminClient.addToTeam(team.id, receiver.id);
|
||||
|
||||
// # Create a private channel with sender and receiver
|
||||
const channelName = `bor-test-${Date.now().toString(36)}`;
|
||||
const channel = await adminClient.createChannel({
|
||||
team_id: team.id,
|
||||
name: channelName,
|
||||
display_name: `BoR Duration Test ${channelName}`,
|
||||
type: 'P',
|
||||
} as any);
|
||||
await adminClient.addToChannel(receiver.id, channel.id);
|
||||
|
||||
// # Login as admin (sender) and post BoR message
|
||||
const {channelsPage: senderChannelsPage} = await pw.testBrowser.login(adminUser);
|
||||
await senderChannelsPage.goto(team.name, channelName);
|
||||
await senderChannelsPage.toBeVisible();
|
||||
await adminClient.patchConfig({
|
||||
ServiceSettings: {
|
||||
EnableBurnOnRead: true,
|
||||
BurnOnReadDurationSeconds: 300,
|
||||
BurnOnReadMaximumTimeToLiveSeconds: 604800,
|
||||
},
|
||||
});
|
||||
|
||||
// # Toggle BoR on and post message
|
||||
await senderChannelsPage.centerView.postCreate.toggleBurnOnRead();
|
||||
const messageContent = `Duration test ${Date.now()}`;
|
||||
await senderChannelsPage.postMessage(messageContent);
|
||||
|
||||
// # Login as receiver and reveal the message
|
||||
const {channelsPage: receiverChannelsPage, page: receiverPage} = await pw.testBrowser.login(receiver as any);
|
||||
await receiverChannelsPage.goto(team.name, channelName);
|
||||
await receiverChannelsPage.toBeVisible();
|
||||
|
||||
// # Wait for the concealed placeholder to be visible and enabled (not loading)
|
||||
const concealedPlaceholder = receiverPage.locator('.BurnOnReadConcealedPlaceholder').first();
|
||||
await expect(concealedPlaceholder).toBeVisible({timeout: 10000});
|
||||
|
||||
// Wait for it to not be in loading state
|
||||
await expect(concealedPlaceholder).not.toHaveClass(/BurnOnReadConcealedPlaceholder--loading/, {timeout: 10000});
|
||||
await expect(concealedPlaceholder).toBeEnabled({timeout: 5000});
|
||||
|
||||
// Re-apply guard: TTL is set by the server at reveal time; ensure BurnOnReadDurationSeconds
|
||||
// is still 300 at the moment of reveal — a concurrent initSetup() may have reset it.
|
||||
await adminClient.patchConfig({
|
||||
ServiceSettings: {
|
||||
EnableBurnOnRead: true,
|
||||
BurnOnReadDurationSeconds: 300,
|
||||
BurnOnReadMaximumTimeToLiveSeconds: 604800,
|
||||
},
|
||||
});
|
||||
|
||||
// # Click to reveal the concealed message
|
||||
await concealedPlaceholder.click();
|
||||
|
||||
// # Confirm reveal in modal if it appears
|
||||
const confirmModal = receiverPage.locator('.BurnOnReadConfirmationModal');
|
||||
if (await confirmModal.isVisible({timeout: 2000}).catch(() => false)) {
|
||||
const confirmButton = confirmModal.getByRole('button', {name: /reveal/i});
|
||||
await confirmButton.click();
|
||||
}
|
||||
|
||||
// * Verify timer chip shows approximately 5 minutes (between 4:10 and 5:00)
|
||||
const timerChip = receiverPage.locator('.BurnOnReadTimerChip').first();
|
||||
await expect(timerChip).toBeVisible({timeout: 15000});
|
||||
|
||||
const timerText = await timerChip.textContent();
|
||||
// Timer format is "M:SS" or "MM:SS", should be close to 5:00
|
||||
const match = timerText?.match(/(\d+):(\d{2})/);
|
||||
expect(match).not.toBeNull();
|
||||
|
||||
if (match) {
|
||||
const minutes = parseInt(match[1], 10);
|
||||
const seconds = parseInt(match[2], 10);
|
||||
const totalSeconds = minutes * 60 + seconds;
|
||||
|
||||
// Should be between 4:10 (250s) and 5:00 (300s) accounting for test execution time
|
||||
expect(totalSeconds).toBeGreaterThanOrEqual(250);
|
||||
expect(totalSeconds).toBeLessThanOrEqual(300);
|
||||
}
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user