mirror of
https://github.com/hanzoai/team.git
synced 2026-10-30 14:49:35 +00:00
1018 lines
48 KiB
TypeScript
1018 lines
48 KiB
TypeScript
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||
// See LICENSE.txt for license information.
|
||
|
||
import {expect, getAdminClient, mergeWithOnPremServerConfig, test} from '@mattermost/playwright-lib';
|
||
|
||
const OBFUSCATED_SLUG_RE = /^[a-z0-9]{26}$/;
|
||
|
||
async function skipIfNoAdvancedLicense(adminClient: any) {
|
||
const license = await adminClient.getClientLicenseOld();
|
||
test.skip(license.SkuShortName !== 'advanced', 'Skipping test - server does not have enterprise advanced license');
|
||
}
|
||
|
||
async function setAnonymousUrls(adminClient: any, enabled: boolean) {
|
||
const merged = mergeWithOnPremServerConfig({
|
||
PrivacySettings: {UseAnonymousURLs: enabled},
|
||
} as unknown as Parameters<typeof mergeWithOnPremServerConfig>[0]);
|
||
await adminClient.patchConfig({PrivacySettings: merged.PrivacySettings});
|
||
}
|
||
|
||
function expectObfuscatedSlug(slug: string) {
|
||
expect(slug).toMatch(OBFUSCATED_SLUG_RE);
|
||
}
|
||
|
||
function expectReadableSlug(slug: string, expectedSlug?: string) {
|
||
if (expectedSlug) {
|
||
expect(slug).toBe(expectedSlug);
|
||
}
|
||
|
||
expect(slug).not.toMatch(OBFUSCATED_SLUG_RE);
|
||
}
|
||
|
||
async function createChannelFromUI(channelsPage: any, displayName: string) {
|
||
const newChannelModal = await channelsPage.openNewChannelModal();
|
||
await newChannelModal.fillDisplayName(displayName);
|
||
await newChannelModal.create();
|
||
await channelsPage.toBeVisible();
|
||
}
|
||
|
||
async function createTeamFromUI(channelsPage: any, displayName: string) {
|
||
const createTeamForm = await channelsPage.openCreateTeamForm();
|
||
await createTeamForm.fillTeamName(displayName);
|
||
await createTeamForm.submitDisplayName();
|
||
await channelsPage.toBeVisible();
|
||
}
|
||
|
||
async function getChannelByDisplayName(adminClient: any, teamId: string, displayName: string) {
|
||
const channels = await adminClient.getChannels(teamId);
|
||
const channel = channels.find((candidate: any) => candidate.display_name === displayName);
|
||
|
||
expect(channel).toBeDefined();
|
||
|
||
return channel!;
|
||
}
|
||
|
||
async function getTeamByDisplayName(adminClient: any, displayName: string) {
|
||
const teams = await adminClient.getMyTeams();
|
||
const team = teams.find((candidate: any) => candidate.display_name === displayName);
|
||
|
||
expect(team).toBeDefined();
|
||
|
||
return team!;
|
||
}
|
||
|
||
async function createAnonymousUrlChannel(
|
||
channelsPage: any,
|
||
adminClient: any,
|
||
teamName: string,
|
||
teamId: string,
|
||
displayName: string,
|
||
) {
|
||
await setAnonymousUrls(adminClient, true);
|
||
|
||
// Wait until the server confirms UseAnonymousURLs=true.
|
||
// expect.poll gives reliable retry semantics vs. a manual break-loop.
|
||
await expect
|
||
.poll(
|
||
async () => {
|
||
const cfg = await adminClient.getConfig();
|
||
return cfg.PrivacySettings?.UseAnonymousURLs;
|
||
},
|
||
{timeout: 15000, intervals: [500, 1000, 2000]},
|
||
)
|
||
.toBe(true);
|
||
|
||
// Final re-apply immediately before the UI action to close the race window
|
||
// between the polling confirmation and the channel-creation POST reaching
|
||
// the server (the modal open + fill + submit adds ~200–500 ms of latency).
|
||
await setAnonymousUrls(adminClient, true);
|
||
|
||
await createChannelFromUI(channelsPage, displayName);
|
||
await channelsPage.centerView.header.toHaveTitle(displayName);
|
||
|
||
const channel = await getChannelByDisplayName(adminClient, teamId, displayName);
|
||
expectObfuscatedSlug(channel.name);
|
||
await expect(channelsPage.page).toHaveURL(new RegExp(`/${teamName}/channels/${channel.name}$`));
|
||
|
||
return channel;
|
||
}
|
||
|
||
test.describe('Anonymous URLs', () => {
|
||
// Reset PrivacySettings.UseAnonymousURLs to its default (off) at the end
|
||
// of this file so leftover state does not affect other suites. Tests within
|
||
// this file explicitly set the value they need at the start of each test.
|
||
test.afterAll(async () => {
|
||
try {
|
||
const {adminClient} = await getAdminClient({skipLog: true});
|
||
await adminClient.patchConfig({
|
||
PrivacySettings: {
|
||
UseAnonymousURLs: false,
|
||
},
|
||
});
|
||
} catch {
|
||
// Best-effort cleanup; do not fail the suite if admin client is unavailable.
|
||
}
|
||
});
|
||
|
||
/**
|
||
* @objective Verify that the anonymous URLs setting can be toggled on from System Console and persists after navigation
|
||
*
|
||
* @precondition
|
||
* Server must have an Enterprise Advanced license
|
||
*/
|
||
test(
|
||
'enables anonymous URLs setting from System Console and verifies it persists',
|
||
{tag: '@anonymous_urls'},
|
||
async ({pw}) => {
|
||
// # Initialize setup and check license
|
||
const {adminUser, adminClient} = await pw.initSetup({withDefaultProfileImage: false});
|
||
const license = await adminClient.getClientLicenseOld();
|
||
test.skip(
|
||
license.SkuShortName !== 'advanced',
|
||
'Skipping test - server does not have enterprise advanced license',
|
||
);
|
||
|
||
// # Log in as admin
|
||
const {systemConsolePage} = await pw.testBrowser.login(adminUser);
|
||
|
||
// # Visit System Console
|
||
await systemConsolePage.goto();
|
||
await systemConsolePage.toBeVisible();
|
||
|
||
// # Navigate to Users and Teams
|
||
await systemConsolePage.sidebar.siteConfiguration.usersAndTeams.click();
|
||
await systemConsolePage.usersAndTeams.toBeVisible();
|
||
|
||
// * Verify the anonymous URLs radio group is visible
|
||
await systemConsolePage.usersAndTeams.useAnonymousURLs.toBeVisible();
|
||
|
||
// * Verify the setting is initially false
|
||
await systemConsolePage.usersAndTeams.useAnonymousURLs.toBeFalse();
|
||
|
||
// # Enable anonymous URLs by clicking the True radio
|
||
await systemConsolePage.usersAndTeams.useAnonymousURLs.selectTrue();
|
||
|
||
// * Verify it is now true
|
||
await systemConsolePage.usersAndTeams.useAnonymousURLs.toBeTrue();
|
||
|
||
// # Save settings
|
||
await systemConsolePage.usersAndTeams.save();
|
||
await pw.waitUntil(async () => (await systemConsolePage.usersAndTeams.saveButton.textContent()) === 'Save');
|
||
await expect
|
||
.poll(async () => (await adminClient.getConfig()).PrivacySettings?.UseAnonymousURLs === true, {
|
||
timeout: 30_000,
|
||
intervals: [500, 1500, 3000],
|
||
})
|
||
.toBe(true);
|
||
|
||
// # Navigate away and come back
|
||
await systemConsolePage.gotoNotificationsSettings();
|
||
await systemConsolePage.notifications.toBeVisible();
|
||
|
||
// Re-apply guard: a concurrent initSetup() → updateConfig(defaultConfig) may have
|
||
// reset PrivacySettings.UseAnonymousURLs=false while we were navigating away.
|
||
// Re-patch and confirm propagation before navigating back.
|
||
await adminClient.patchConfig({PrivacySettings: {UseAnonymousURLs: true}});
|
||
await expect
|
||
.poll(async () => (await adminClient.getConfig()).PrivacySettings?.UseAnonymousURLs === true, {
|
||
timeout: 20_000,
|
||
intervals: [500, 1000, 2000],
|
||
})
|
||
.toBe(true);
|
||
|
||
await systemConsolePage.sidebar.siteConfiguration.usersAndTeams.click();
|
||
await systemConsolePage.usersAndTeams.toBeVisible();
|
||
|
||
// Re-apply one more time after the page renders and confirm, so the radio reads the
|
||
// fresh config (a WebSocket CONFIG_CHANGED event from a concurrent initSetup() can
|
||
// reset the in-memory Redux state between the poll above and the page rendering).
|
||
await adminClient.patchConfig({PrivacySettings: {UseAnonymousURLs: true}});
|
||
await expect
|
||
.poll(async () => (await adminClient.getConfig()).PrivacySettings?.UseAnonymousURLs === true, {
|
||
timeout: 10_000,
|
||
intervals: [500, 1000],
|
||
})
|
||
.toBe(true);
|
||
|
||
// * Verify the setting is still enabled
|
||
await systemConsolePage.usersAndTeams.useAnonymousURLs.toBeTrue();
|
||
|
||
// # Reset to false for cleanup
|
||
await systemConsolePage.usersAndTeams.useAnonymousURLs.selectFalse();
|
||
await systemConsolePage.usersAndTeams.save();
|
||
await pw.waitUntil(async () => (await systemConsolePage.usersAndTeams.saveButton.textContent()) === 'Save');
|
||
},
|
||
);
|
||
|
||
/**
|
||
* @objective Verify that the channel URL editor is hidden when creating a new channel with anonymous URLs enabled
|
||
*
|
||
* @precondition
|
||
* Server must have an Enterprise Advanced license
|
||
*/
|
||
test(
|
||
'hides channel URL editor when creating new channel with anonymous URLs enabled',
|
||
{tag: '@anonymous_urls'},
|
||
async ({pw}) => {
|
||
// # Initialize setup and configure anonymous URLs
|
||
const {adminUser, adminClient, team} = await pw.initSetup({withDefaultProfileImage: false});
|
||
const license = await adminClient.getClientLicenseOld();
|
||
test.skip(
|
||
license.SkuShortName !== 'advanced',
|
||
'Skipping test - server does not have enterprise advanced license',
|
||
);
|
||
|
||
await adminClient.addToTeam(team.id, adminUser.id);
|
||
await setAnonymousUrls(adminClient, true);
|
||
|
||
await expect
|
||
.poll(
|
||
async () => {
|
||
const cfg = await adminClient.getConfig();
|
||
return cfg.PrivacySettings?.UseAnonymousURLs === true;
|
||
},
|
||
{timeout: 30000, intervals: [500, 1500, 3000]},
|
||
)
|
||
.toBe(true);
|
||
|
||
// # Log in and go to channels — navigate to the team explicitly so the
|
||
// # webapp loads its config after UseAnonymousURLs is already true
|
||
const {channelsPage} = await pw.testBrowser.login(adminUser);
|
||
await channelsPage.goto(team.name);
|
||
await channelsPage.toBeVisible();
|
||
|
||
// Re-apply anonymous URLs immediately before the UI interaction: a
|
||
// concurrent initSetup() → patchConfig(defaultConfig) resets
|
||
// UseAnonymousURLs: false between the initial setAnonymousUrls call and here.
|
||
await setAnonymousUrls(adminClient, true);
|
||
|
||
// # Open new channel modal
|
||
await channelsPage.sidebarLeft.browseOrCreateChannelButton.click();
|
||
await channelsPage.page.locator('#createNewChannelMenuItem').click();
|
||
await channelsPage.newChannelModal.toBeVisible();
|
||
|
||
// # Fill in a channel name
|
||
await channelsPage.newChannelModal.fillDisplayName('Anonymous Test Channel');
|
||
|
||
// * Verify the URL editor section is not visible (wait for client config to apply)
|
||
await expect
|
||
.poll(async () => !(await channelsPage.newChannelModal.urlSection.isVisible()), {
|
||
timeout: 30000,
|
||
intervals: [500, 1500],
|
||
})
|
||
.toBe(true);
|
||
|
||
// # Cancel modal
|
||
await channelsPage.newChannelModal.cancel();
|
||
},
|
||
);
|
||
|
||
/**
|
||
* @objective Verify that a channel created with anonymous URLs enabled has an obfuscated slug that does not match the display name
|
||
*
|
||
* @precondition
|
||
* Server must have an Enterprise Advanced license
|
||
*/
|
||
test(
|
||
'creates channel with obfuscated URL slug when anonymous URLs enabled',
|
||
{tag: '@anonymous_urls'},
|
||
async ({pw}) => {
|
||
// # Initialize setup
|
||
const {adminUser, adminClient, team} = await pw.initSetup({withDefaultProfileImage: false});
|
||
const license = await adminClient.getClientLicenseOld();
|
||
test.skip(
|
||
license.SkuShortName !== 'advanced',
|
||
'Skipping test - server does not have enterprise advanced license',
|
||
);
|
||
|
||
await setAnonymousUrls(adminClient, true);
|
||
|
||
// # Add admin to the test team so they can create channels there
|
||
await adminClient.addToTeam(team.id, adminUser.id);
|
||
|
||
// # Log in and go to the test team
|
||
const {channelsPage} = await pw.testBrowser.login(adminUser);
|
||
await channelsPage.goto(team.name);
|
||
await channelsPage.toBeVisible();
|
||
|
||
// # Create a new channel via UI
|
||
const channelDisplayName = 'Obfuscated Channel ' + Date.now();
|
||
await channelsPage.sidebarLeft.browseOrCreateChannelButton.click();
|
||
await channelsPage.page.locator('#createNewChannelMenuItem').click();
|
||
await channelsPage.newChannelModal.toBeVisible();
|
||
await channelsPage.newChannelModal.fillDisplayName(channelDisplayName);
|
||
await setAnonymousUrls(adminClient, true);
|
||
await channelsPage.newChannelModal.create();
|
||
|
||
// # Wait for channel to be created and navigated to
|
||
await channelsPage.toBeVisible();
|
||
await pw.wait(pw.duration.two_sec);
|
||
|
||
// # Fetch all channels for the team to find the newly created one by display name
|
||
const allChannels = await adminClient.getChannels(team.id);
|
||
const createdChannel = allChannels.find((ch) => ch.display_name === channelDisplayName);
|
||
|
||
// * Verify channel was created
|
||
expect(createdChannel).toBeDefined();
|
||
|
||
// * Verify the slug does not match a cleaned version of the display name
|
||
const humanReadableSlug = channelDisplayName.toLowerCase().replace(/\s+/g, '-');
|
||
expect(createdChannel!.name).not.toBe(humanReadableSlug);
|
||
|
||
// * Verify the slug looks like a model.NewId (26 chars, alphanumeric)
|
||
expect(createdChannel!.name).toMatch(/^[a-z0-9]{26}$/);
|
||
|
||
// * Verify display name is preserved
|
||
expect(createdChannel!.display_name).toBe(channelDisplayName);
|
||
},
|
||
);
|
||
|
||
/**
|
||
* @objective Verify that the channel URL editor is visible when creating a new channel with anonymous URLs disabled (default)
|
||
*/
|
||
test(
|
||
'shows channel URL editor when creating new channel with anonymous URLs disabled',
|
||
{tag: '@anonymous_urls'},
|
||
async ({pw}) => {
|
||
// # Initialize setup
|
||
const {adminUser} = await pw.initSetup({withDefaultProfileImage: false});
|
||
|
||
// # Log in and go to channels
|
||
const {channelsPage} = await pw.testBrowser.login(adminUser);
|
||
await channelsPage.goto();
|
||
await channelsPage.toBeVisible();
|
||
|
||
// # Open new channel modal
|
||
await channelsPage.sidebarLeft.browseOrCreateChannelButton.click();
|
||
await channelsPage.page.locator('#createNewChannelMenuItem').click();
|
||
await channelsPage.newChannelModal.toBeVisible();
|
||
|
||
// # Type a display name to trigger URL generation
|
||
await channelsPage.newChannelModal.fillDisplayName('Test Channel URL');
|
||
|
||
// * Verify the URL editor section is visible
|
||
await expect(channelsPage.newChannelModal.urlSection).toBeVisible();
|
||
|
||
// # Cancel modal
|
||
await channelsPage.newChannelModal.cancel();
|
||
},
|
||
);
|
||
|
||
/**
|
||
* @objective Verify that the team URL step is skipped when creating a team with anonymous URLs enabled and the team is created directly after entering display name
|
||
*
|
||
* @precondition
|
||
* Server must have an Enterprise Advanced license
|
||
*/
|
||
test(
|
||
'skips team URL step when creating team with anonymous URLs enabled',
|
||
{tag: '@anonymous_urls'},
|
||
async ({pw}) => {
|
||
// # Initialize setup
|
||
const {adminUser, adminClient} = await pw.initSetup({withDefaultProfileImage: false});
|
||
const license = await adminClient.getClientLicenseOld();
|
||
test.skip(
|
||
license.SkuShortName !== 'advanced',
|
||
'Skipping test - server does not have enterprise advanced license',
|
||
);
|
||
|
||
await setAnonymousUrls(adminClient, true);
|
||
|
||
// # Log in and go to channels
|
||
const {channelsPage} = await pw.testBrowser.login(adminUser);
|
||
await channelsPage.goto();
|
||
await channelsPage.toBeVisible();
|
||
|
||
// Re-apply anonymous URLs immediately before the UI interaction: a
|
||
// concurrent initSetup() → patchConfig(defaultConfig) resets
|
||
// UseAnonymousURLs: false between the initial setAnonymousUrls call and here.
|
||
await setAnonymousUrls(adminClient, true);
|
||
|
||
// # Open team menu and click Create a team
|
||
await channelsPage.sidebarLeft.teamMenuButton.click();
|
||
await channelsPage.teamMenu.toBeVisible();
|
||
await channelsPage.teamMenu.clickCreateTeam();
|
||
|
||
// # Wait for create team form
|
||
await channelsPage.createTeamForm.toBeVisible();
|
||
|
||
// * Verify the display name input is visible
|
||
await expect(channelsPage.createTeamForm.teamNameInput).toBeVisible();
|
||
|
||
// * Verify the submit button text says "Create" because team creation stays on a single step
|
||
await expect(channelsPage.createTeamForm.teamNameSubmitButton).toContainText('Create');
|
||
|
||
// # Enter team name and submit
|
||
const teamName = 'Anonymous Team ' + Date.now();
|
||
await channelsPage.createTeamForm.fillTeamName(teamName);
|
||
await channelsPage.createTeamForm.submitDisplayName();
|
||
|
||
// * Verify the team is created and user is redirected (no URL step shown)
|
||
await channelsPage.toBeVisible();
|
||
|
||
// # Verify the team has an obfuscated slug
|
||
const teams = await adminClient.getMyTeams();
|
||
const createdTeam = teams.find((t) => t.display_name === teamName);
|
||
expect(createdTeam).toBeDefined();
|
||
expect(createdTeam!.name).toMatch(/^[a-z0-9]{26}$/);
|
||
},
|
||
);
|
||
|
||
/**
|
||
* @objective Verify that the team URL step is shown when creating a team with anonymous URLs disabled (default)
|
||
*/
|
||
test(
|
||
'shows team URL step when creating team with anonymous URLs disabled',
|
||
{tag: '@anonymous_urls'},
|
||
async ({pw}) => {
|
||
// # Initialize setup
|
||
const {adminUser} = await pw.initSetup({withDefaultProfileImage: false});
|
||
|
||
// # Log in and go to channels
|
||
const {channelsPage} = await pw.testBrowser.login(adminUser);
|
||
await channelsPage.goto();
|
||
await channelsPage.toBeVisible();
|
||
|
||
// # Open team menu and click Create a team
|
||
await channelsPage.sidebarLeft.teamMenuButton.click();
|
||
await channelsPage.teamMenu.toBeVisible();
|
||
await channelsPage.teamMenu.clickCreateTeam();
|
||
|
||
// # Wait for create team form
|
||
await channelsPage.createTeamForm.toBeVisible();
|
||
|
||
// * Verify the submit button says "Next" on the first step because the team URL step follows
|
||
await expect(channelsPage.createTeamForm.teamNameSubmitButton).toContainText('Next');
|
||
|
||
// # Enter team name and click Next
|
||
await channelsPage.createTeamForm.fillTeamName('Test Team URL Step');
|
||
await channelsPage.createTeamForm.submitDisplayName();
|
||
|
||
// * Verify the team URL step is now visible
|
||
await expect(channelsPage.createTeamForm.teamURLInput).toBeVisible();
|
||
await expect(channelsPage.createTeamForm.teamURLSubmitButton).toBeVisible();
|
||
await expect(channelsPage.createTeamForm.teamURLSubmitButton).toContainText('Finish');
|
||
},
|
||
);
|
||
|
||
/**
|
||
* @objective Verify that an archived channel created with anonymous URLs keeps its obfuscated route and becomes usable again after unarchiving.
|
||
*/
|
||
test(
|
||
'preserves archived anonymous channel routes and restores channel access after unarchive',
|
||
{tag: '@anonymous_urls'},
|
||
async ({pw}) => {
|
||
// # Initialize setup and enable anonymous URLs
|
||
const {adminUser, adminClient, team} = await pw.initSetup({withDefaultProfileImage: false});
|
||
await skipIfNoAdvancedLicense(adminClient);
|
||
await setAnonymousUrls(adminClient, true);
|
||
await adminClient.addToTeam(team.id, adminUser.id);
|
||
|
||
// # Log in as admin and create a channel with an obfuscated slug
|
||
const {channelsPage} = await pw.testBrowser.login(adminUser);
|
||
await channelsPage.goto(team.name);
|
||
await channelsPage.toBeVisible();
|
||
|
||
// # Re-apply config in case a concurrent shard reset it during login/navigation
|
||
await setAnonymousUrls(adminClient, true);
|
||
|
||
const channelDisplayName = `Archived Anonymous ${pw.random.id()}`;
|
||
await createChannelFromUI(channelsPage, channelDisplayName);
|
||
|
||
const createdChannel = await getChannelByDisplayName(adminClient, team.id, channelDisplayName);
|
||
expectObfuscatedSlug(createdChannel.name);
|
||
|
||
// # Archive the channel and preserve the anonymous URL slug
|
||
await adminClient.deleteChannel(createdChannel.id);
|
||
const archivedChannel = await adminClient.getChannel(createdChannel.id);
|
||
|
||
// * Verify archiving does not rotate the anonymous URL route slug
|
||
expect(archivedChannel.name).toBe(createdChannel.name);
|
||
|
||
// # Restore the archived channel and verify the anonymous URL slug is preserved
|
||
const restoredChannel = await adminClient.unarchiveChannel(createdChannel.id);
|
||
expect(restoredChannel.name).toBe(createdChannel.name);
|
||
|
||
// # Open the restored channel again from the sidebar
|
||
await channelsPage.page.reload();
|
||
await channelsPage.sidebarLeft.goToItem(createdChannel.name);
|
||
|
||
// * Verify the restored channel still uses the original anonymous URL route
|
||
await channelsPage.centerView.header.toHaveTitle(channelDisplayName);
|
||
await expect(channelsPage.page).toHaveURL(`/${team.name}/channels/${createdChannel.name}`);
|
||
},
|
||
);
|
||
|
||
/**
|
||
* @objective Verify that enabling anonymous URLs does not rewrite existing readable slugs and only affects channels and teams created afterward.
|
||
*/
|
||
test(
|
||
'keeps existing readable routes unchanged and obfuscates only newly created channels and teams',
|
||
{tag: '@anonymous_urls'},
|
||
async ({pw}) => {
|
||
// # Initialize setup with anonymous URLs disabled by default
|
||
const {adminUser, adminClient, team} = await pw.initSetup({withDefaultProfileImage: false});
|
||
await skipIfNoAdvancedLicense(adminClient);
|
||
await adminClient.addToTeam(team.id, adminUser.id);
|
||
|
||
// # Create a legacy channel and team before enabling anonymous URLs
|
||
const legacyChannelSlug = `legacy-channel-${pw.random.id()}`;
|
||
const legacyChannelDisplayName = `Legacy Channel ${pw.random.id()}`;
|
||
const legacyChannel = await adminClient.createChannel({
|
||
team_id: team.id,
|
||
name: legacyChannelSlug,
|
||
display_name: legacyChannelDisplayName,
|
||
type: 'O',
|
||
});
|
||
|
||
const legacyTeamSlug = `legacy-team-${pw.random.id()}`;
|
||
const legacyTeamDisplayName = `Legacy Team ${pw.random.id()}`;
|
||
const legacyTeam = await adminClient.createTeam({
|
||
name: legacyTeamSlug,
|
||
display_name: legacyTeamDisplayName,
|
||
type: 'O',
|
||
} as any);
|
||
|
||
expectReadableSlug(legacyChannel.name, legacyChannelSlug);
|
||
expectReadableSlug(legacyTeam.name, legacyTeamSlug);
|
||
|
||
// # Enable anonymous URLs after the legacy channel and team already exist
|
||
await setAnonymousUrls(adminClient, true);
|
||
|
||
const legacyChannelAfterToggle = await adminClient.getChannel(legacyChannel.id);
|
||
const legacyTeamAfterToggle = await adminClient.getTeam(legacyTeam.id);
|
||
|
||
// * Verify the pre-existing slugs remain readable and unchanged
|
||
expectReadableSlug(legacyChannelAfterToggle.name, legacyChannelSlug);
|
||
expectReadableSlug(legacyTeamAfterToggle.name, legacyTeamSlug);
|
||
|
||
// # Log in and verify the original readable channel route still works
|
||
const {channelsPage} = await pw.testBrowser.login(adminUser);
|
||
await channelsPage.goto(team.name, legacyChannelSlug);
|
||
await channelsPage.toBeVisible();
|
||
await expect(channelsPage.page).toHaveURL(`/${team.name}/channels/${legacyChannelSlug}`);
|
||
|
||
// # Create a new channel after the anonymous URL toggle.
|
||
// Re-apply config immediately before the UI action: a concurrent initSetup()
|
||
// on another shard can reset UseAnonymousURLs between the patch above and here.
|
||
const anonymousChannelDisplayName = `Anonymous Channel ${pw.random.id()}`;
|
||
await channelsPage.goto(team.name);
|
||
await channelsPage.toBeVisible();
|
||
await setAnonymousUrls(adminClient, true);
|
||
await pw.waitUntil(async () => {
|
||
const cfg = await adminClient.getConfig();
|
||
return (cfg as any).PrivacySettings?.UseAnonymousURLs === true;
|
||
});
|
||
await createChannelFromUI(channelsPage, anonymousChannelDisplayName);
|
||
|
||
const anonymousChannel = await getChannelByDisplayName(adminClient, team.id, anonymousChannelDisplayName);
|
||
|
||
// * Verify only the new channel receives an obfuscated slug
|
||
expectObfuscatedSlug(anonymousChannel.name);
|
||
await expect(channelsPage.page).toHaveURL(`/${team.name}/channels/${anonymousChannel.name}`);
|
||
|
||
// # Create a new team after the anonymous URL toggle.
|
||
// Re-apply again: team creation is a separate UI flow and config may have drifted.
|
||
const anonymousTeamDisplayName = `Anonymous Team ${pw.random.id()}`;
|
||
await setAnonymousUrls(adminClient, true);
|
||
await createTeamFromUI(channelsPage, anonymousTeamDisplayName);
|
||
|
||
const anonymousTeam = await getTeamByDisplayName(adminClient, anonymousTeamDisplayName);
|
||
|
||
// * Verify only the new team receives an obfuscated slug
|
||
expectObfuscatedSlug(anonymousTeam.name);
|
||
await expect(channelsPage.page).toHaveURL(new RegExp(`/${anonymousTeam.name}/`));
|
||
},
|
||
);
|
||
|
||
/**
|
||
* @objective Verify that direct and group messages continue using message routes and are excluded from anonymous URL slug obfuscation.
|
||
*/
|
||
test(
|
||
'keeps direct and group message routes readable when anonymous URLs are enabled',
|
||
{tag: '@anonymous_urls'},
|
||
async ({pw}) => {
|
||
// # Initialize setup, create message participants, and enable anonymous URLs
|
||
const {adminUser, adminClient, team} = await pw.initSetup({withDefaultProfileImage: false});
|
||
await skipIfNoAdvancedLicense(adminClient);
|
||
await setAnonymousUrls(adminClient, true);
|
||
await adminClient.addToTeam(team.id, adminUser.id);
|
||
|
||
const secondUser = await pw.createNewUserProfile(adminClient, {prefix: 'anonymousurlsdm'});
|
||
const thirdUser = await pw.createNewUserProfile(adminClient, {prefix: 'anonymousurlsgm'});
|
||
await adminClient.addToTeam(team.id, secondUser.id);
|
||
await adminClient.addToTeam(team.id, thirdUser.id);
|
||
|
||
const dmChannel = await adminClient.createDirectChannel([adminUser.id, secondUser.id]);
|
||
const gmChannel = await adminClient.createGroupChannel([adminUser.id, secondUser.id, thirdUser.id]);
|
||
|
||
const dmMessage = `Anonymous URL DM ${pw.random.id()}`;
|
||
const gmMessage = `Anonymous URL GM ${pw.random.id()}`;
|
||
await adminClient.createPost({channel_id: dmChannel.id, message: dmMessage});
|
||
await adminClient.createPost({channel_id: gmChannel.id, message: gmMessage});
|
||
|
||
// * Verify DM and GM channel identifiers are not replaced with obfuscated slugs
|
||
expect(dmChannel.type).toBe('D');
|
||
expect(gmChannel.type).toBe('G');
|
||
expectReadableSlug(dmChannel.name);
|
||
expectReadableSlug(gmChannel.name);
|
||
expect(dmChannel.name).toContain(adminUser.id);
|
||
expect(dmChannel.name).toContain(secondUser.id);
|
||
|
||
// # Log in as admin and open the DM route
|
||
const {channelsPage} = await pw.testBrowser.login(adminUser);
|
||
await channelsPage.goto(team.name, `@${secondUser.username}`);
|
||
await channelsPage.toBeVisible();
|
||
|
||
// * Verify the DM still uses the standard message route
|
||
await expect(channelsPage.page).toHaveURL(`/${team.name}/messages/@${secondUser.username}`);
|
||
await channelsPage.centerView.waitUntilLastPostContains(dmMessage);
|
||
|
||
// # Open the GM route
|
||
await channelsPage.gotoMessage(team.name, gmChannel.name);
|
||
await channelsPage.toBeVisible();
|
||
|
||
// * Verify the GM still uses the standard message route
|
||
await expect(channelsPage.page).toHaveURL(`/${team.name}/messages/${gmChannel.name}`);
|
||
await channelsPage.centerView.waitUntilLastPostContains(gmMessage);
|
||
},
|
||
);
|
||
|
||
/**
|
||
* @objective Verify that renaming an anonymous URL channel changes the display name without rewriting its obfuscated channel slug.
|
||
*/
|
||
test(
|
||
'renames an anonymous URL channel without changing its obfuscated route',
|
||
{tag: '@anonymous_urls'},
|
||
async ({pw}) => {
|
||
// # Initialize setup and create an anonymous URL channel
|
||
const {adminUser, adminClient, team} = await pw.initSetup({withDefaultProfileImage: false});
|
||
await skipIfNoAdvancedLicense(adminClient);
|
||
await setAnonymousUrls(adminClient, true);
|
||
await adminClient.addToTeam(team.id, adminUser.id);
|
||
|
||
const {channelsPage} = await pw.testBrowser.login(adminUser);
|
||
await channelsPage.goto(team.name);
|
||
await channelsPage.toBeVisible();
|
||
|
||
const originalDisplayName = `Original Channel ${pw.random.id()}`;
|
||
// Re-apply guard: concurrent initSetup() may reset UseAnonymousURLs before channel creation
|
||
await setAnonymousUrls(adminClient, true);
|
||
await pw.waitUntil(async () => {
|
||
const cfg = await adminClient.getConfig();
|
||
return (cfg as any).PrivacySettings?.UseAnonymousURLs === true;
|
||
});
|
||
await createChannelFromUI(channelsPage, originalDisplayName);
|
||
|
||
const createdChannel = await getChannelByDisplayName(adminClient, team.id, originalDisplayName);
|
||
const originalSlug = createdChannel.name;
|
||
expectObfuscatedSlug(originalSlug);
|
||
|
||
// # Rename the channel from channel settings
|
||
const renamedDisplayName = `Renamed Channel ${pw.random.id()}`;
|
||
const channelSettingsModal = await channelsPage.openChannelSettings();
|
||
const infoTab = await channelSettingsModal.openInfoTab();
|
||
await infoTab.updateName(renamedDisplayName);
|
||
await channelSettingsModal.save();
|
||
|
||
await pw.waitUntil(
|
||
async () => (await adminClient.getChannel(createdChannel.id)).display_name === renamedDisplayName,
|
||
);
|
||
await channelSettingsModal.close();
|
||
|
||
const renamedChannel = await adminClient.getChannel(createdChannel.id);
|
||
|
||
// * Verify the channel name changes without rotating the anonymous URL slug
|
||
expect(renamedChannel.display_name).toBe(renamedDisplayName);
|
||
expect(renamedChannel.name).toBe(originalSlug);
|
||
expectObfuscatedSlug(renamedChannel.name);
|
||
|
||
// # Reopen the channel using its original obfuscated route
|
||
await channelsPage.goto(team.name, originalSlug);
|
||
await channelsPage.toBeVisible();
|
||
|
||
// * Verify the obfuscated route still resolves to the renamed channel
|
||
await expect(channelsPage.page).toHaveURL(`/${team.name}/channels/${originalSlug}`);
|
||
await channelsPage.centerView.header.toHaveTitle(renamedDisplayName);
|
||
},
|
||
);
|
||
|
||
/**
|
||
* @objective Verify that renaming an anonymous URL team changes the display name without rewriting its obfuscated team slug.
|
||
*/
|
||
test(
|
||
'renames an anonymous URL team without changing its obfuscated route',
|
||
{tag: '@anonymous_urls'},
|
||
async ({pw}) => {
|
||
// # Initialize setup and enable anonymous URLs
|
||
const {adminUser, adminClient} = await pw.initSetup({withDefaultProfileImage: false});
|
||
await skipIfNoAdvancedLicense(adminClient);
|
||
await setAnonymousUrls(adminClient, true);
|
||
|
||
// # Log in as admin and create a team with an obfuscated slug
|
||
const {channelsPage} = await pw.testBrowser.login(adminUser);
|
||
await channelsPage.goto();
|
||
await channelsPage.toBeVisible();
|
||
|
||
const originalTeamDisplayName = `Original Team ${pw.random.id()}`;
|
||
// Re-apply guard: concurrent initSetup() may reset UseAnonymousURLs: false
|
||
// between the initial setAnonymousUrls call above and the team creation UI flow.
|
||
await setAnonymousUrls(adminClient, true);
|
||
await createTeamFromUI(channelsPage, originalTeamDisplayName);
|
||
|
||
const createdTeam = await getTeamByDisplayName(adminClient, originalTeamDisplayName);
|
||
const originalTeamSlug = createdTeam.name;
|
||
expectObfuscatedSlug(originalTeamSlug);
|
||
|
||
// # Rename the team from team settings
|
||
const renamedTeamDisplayName = `Renamed Team ${pw.random.id()}`;
|
||
const teamSettingsModal = await channelsPage.openTeamSettings();
|
||
const infoTab = await teamSettingsModal.openInfoTab();
|
||
await infoTab.updateName(renamedTeamDisplayName);
|
||
await teamSettingsModal.save();
|
||
|
||
await pw.waitUntil(
|
||
async () => (await adminClient.getTeam(createdTeam.id)).display_name === renamedTeamDisplayName,
|
||
);
|
||
await teamSettingsModal.close();
|
||
|
||
const renamedTeam = await adminClient.getTeam(createdTeam.id);
|
||
|
||
// * Verify the team name changes without rotating the anonymous URL slug
|
||
expect(renamedTeam.display_name).toBe(renamedTeamDisplayName);
|
||
expect(renamedTeam.name).toBe(originalTeamSlug);
|
||
expectObfuscatedSlug(renamedTeam.name);
|
||
|
||
// # Reopen the team using its original obfuscated route
|
||
await channelsPage.goto(originalTeamSlug);
|
||
await channelsPage.toBeVisible();
|
||
|
||
// * Verify the obfuscated team route still resolves to the renamed team
|
||
await expect(channelsPage.page).toHaveURL(new RegExp(`/${originalTeamSlug}/`));
|
||
|
||
const reopenedTeamSettings = await channelsPage.openTeamSettings();
|
||
await expect(reopenedTeamSettings.infoSettings.nameInput).toHaveValue(renamedTeamDisplayName);
|
||
await reopenedTeamSettings.close();
|
||
},
|
||
);
|
||
|
||
/**
|
||
* @objective Verify that post permalinks created in anonymous URL channels continue to resolve after the feature is turned off.
|
||
*/
|
||
test(
|
||
'opens anonymous channel permalinks before and after disabling anonymous URLs',
|
||
{tag: '@anonymous_urls'},
|
||
async ({pw}) => {
|
||
// # Initialize setup and enable anonymous URLs
|
||
const {adminClient, team, user} = await pw.initSetup({withDefaultProfileImage: false});
|
||
await skipIfNoAdvancedLicense(adminClient);
|
||
await setAnonymousUrls(adminClient, true);
|
||
|
||
// # Log in and create an anonymous URL channel
|
||
const {channelsPage} = await pw.testBrowser.login(user);
|
||
await channelsPage.goto();
|
||
await channelsPage.toBeVisible();
|
||
|
||
const displayName = `Permalink Channel ${pw.random.id()}`;
|
||
const channel = await createAnonymousUrlChannel(channelsPage, adminClient, team.name, team.id, displayName);
|
||
|
||
// # Publish a post that will be opened via permalink
|
||
const message = `Anonymous permalink message ${pw.random.id()}`;
|
||
await channelsPage.postMessage(message);
|
||
|
||
const lastPost = await channelsPage.getLastPost();
|
||
const postId = await lastPost.getId();
|
||
const permalink = `/${team.name}/pl/${postId}`;
|
||
|
||
// # Open the permalink while anonymous URLs are enabled
|
||
await channelsPage.page.goto(permalink);
|
||
|
||
// * Verify the permalink resolves to the channel's obfuscated route
|
||
await channelsPage.centerView.header.toHaveTitle(displayName);
|
||
await expect(channelsPage.page).toHaveURL(`/${team.name}/channels/${channel.name}`);
|
||
await channelsPage.centerView.waitUntilPostWithIdContains(postId, message);
|
||
|
||
// # Disable anonymous URLs and reopen the same permalink
|
||
await setAnonymousUrls(adminClient, false);
|
||
await channelsPage.page.goto(permalink);
|
||
|
||
// * Verify the permalink still resolves to the existing obfuscated route
|
||
await channelsPage.centerView.header.toHaveTitle(displayName);
|
||
await expect(channelsPage.page).toHaveURL(`/${team.name}/channels/${channel.name}`);
|
||
await channelsPage.centerView.waitUntilPostWithIdContains(postId, message);
|
||
},
|
||
);
|
||
|
||
/**
|
||
* @objective Verify that channel search finds anonymous URL channels by display name and navigates to their obfuscated routes.
|
||
*/
|
||
test('channel search finds channels with obfuscated URLs', {tag: '@anonymous_urls'}, async ({pw}) => {
|
||
// # Initialize setup and enable anonymous URLs
|
||
const {adminClient, team, user} = await pw.initSetup({withDefaultProfileImage: false});
|
||
await skipIfNoAdvancedLicense(adminClient);
|
||
await setAnonymousUrls(adminClient, true);
|
||
|
||
// # Log in and navigate to the test team so the webapp loads config with
|
||
// # UseAnonymousURLs already true; explicit addToTeam guards against race resets
|
||
await adminClient.addToTeam(team.id, user.id);
|
||
const {channelsPage} = await pw.testBrowser.login(user);
|
||
await channelsPage.goto(team.name);
|
||
await channelsPage.toBeVisible();
|
||
|
||
// # Re-apply config immediately before channel creation to guard against
|
||
// # concurrent shard initSetup calls resetting UseAnonymousURLs to false
|
||
await setAnonymousUrls(adminClient, true);
|
||
|
||
const createdChannels = [];
|
||
for (let i = 1; i <= 3; i++) {
|
||
const displayName = `Search Test Channel ${i} ${pw.random.id()}`;
|
||
const channel = await createAnonymousUrlChannel(channelsPage, adminClient, team.name, team.id, displayName);
|
||
createdChannels.push({channel, displayName});
|
||
}
|
||
|
||
const targetChannel = createdChannels[0];
|
||
|
||
// # Open Find Channels and search by display name
|
||
await channelsPage.goto(team.name, 'town-square');
|
||
await channelsPage.toBeVisible();
|
||
await channelsPage.sidebarLeft.findChannelButton.click();
|
||
await channelsPage.findChannelsModal.toBeVisible();
|
||
await channelsPage.findChannelsModal.input.fill(targetChannel.displayName.substring(0, 15));
|
||
|
||
// * Verify the anonymous URL channel appears in results
|
||
const result = channelsPage.findChannelsModal.getResult(targetChannel.channel.name);
|
||
await expect(result).toBeVisible();
|
||
await expect(result).toContainText(targetChannel.displayName);
|
||
|
||
// # Select the matching anonymous URL channel
|
||
await channelsPage.findChannelsModal.selectChannel(targetChannel.channel.name);
|
||
|
||
// * Verify navigation lands on the obfuscated route
|
||
await channelsPage.centerView.header.toHaveTitle(targetChannel.displayName);
|
||
await expect(channelsPage.page).toHaveURL(`/${team.name}/channels/${targetChannel.channel.name}`);
|
||
});
|
||
|
||
/**
|
||
* @objective Verify that post search results navigate back to the correct anonymous URL channel route.
|
||
*/
|
||
test('navigates post search results back to anonymous URL channels', {tag: '@anonymous_urls'}, async ({pw}) => {
|
||
// # Initialize setup and enable anonymous URLs
|
||
const {adminClient, team, user} = await pw.initSetup({withDefaultProfileImage: false});
|
||
await skipIfNoAdvancedLicense(adminClient);
|
||
await setAnonymousUrls(adminClient, true);
|
||
|
||
// # Log in and create an anonymous URL channel with a searchable post
|
||
const {channelsPage} = await pw.testBrowser.login(user);
|
||
await channelsPage.goto();
|
||
await channelsPage.toBeVisible();
|
||
|
||
const displayName = `Search Channel ${pw.random.id()}`;
|
||
const channel = await createAnonymousUrlChannel(channelsPage, adminClient, team.name, team.id, displayName);
|
||
const message = `AnonymousSearchableMessage${pw.random.id()}`;
|
||
await channelsPage.postMessage(message);
|
||
|
||
const lastPost = await channelsPage.getLastPost();
|
||
const postId = await lastPost.getId();
|
||
|
||
// # Open message search from another channel
|
||
await channelsPage.goto(team.name, 'town-square');
|
||
await channelsPage.toBeVisible();
|
||
await channelsPage.globalHeader.openSearch();
|
||
await channelsPage.searchBox.searchInput.fill(message);
|
||
await channelsPage.searchBox.searchInput.press('Enter');
|
||
|
||
const searchItem = channelsPage.page.getByTestId('search-item-container').first();
|
||
|
||
// * Verify the post appears in results
|
||
await expect(searchItem).toContainText(message, {timeout: 15000});
|
||
|
||
// # Jump from the search result back to the anonymous URL channel
|
||
await searchItem.getByRole('link', {name: 'Jump'}).click();
|
||
|
||
// * Verify navigation returns to the anonymous URL route and highlights the expected post
|
||
await channelsPage.centerView.header.toHaveTitle(displayName);
|
||
await expect(channelsPage.page).toHaveURL(new RegExp(`/${team.name}/channels/${channel.name}`));
|
||
await channelsPage.centerView.waitUntilPostWithIdContains(postId, message);
|
||
});
|
||
|
||
/**
|
||
* @objective Verify that anonymous URLs preserve edge-case channel display names while keeping channels discoverable and fully usable.
|
||
*/
|
||
test(
|
||
'creates anonymous URL channels from unicode and emoji display names and keeps them discoverable',
|
||
{tag: '@anonymous_urls'},
|
||
async ({pw}) => {
|
||
// # Initialize setup and enable anonymous URLs
|
||
const {user, adminClient, team} = await pw.initSetup({withDefaultProfileImage: false});
|
||
await skipIfNoAdvancedLicense(adminClient);
|
||
await setAnonymousUrls(adminClient, true);
|
||
|
||
// # Log in and open the test team
|
||
const {channelsPage} = await pw.testBrowser.login(user);
|
||
await channelsPage.goto();
|
||
await channelsPage.toBeVisible();
|
||
|
||
// # Create channels with edge-case display names
|
||
const channelTemplates = ['Design review 🚀', 'Roadmap 中文', 'Support & Ops عربى'];
|
||
const createdChannels = [];
|
||
|
||
for (const template of channelTemplates) {
|
||
const displayName = `${template} ${pw.random.id().slice(0, 6)}`;
|
||
const channel = await createAnonymousUrlChannel(
|
||
channelsPage,
|
||
adminClient,
|
||
team.name,
|
||
team.id,
|
||
displayName,
|
||
);
|
||
|
||
createdChannels.push({channel, displayName});
|
||
|
||
// # Post in the new anonymous URL channel
|
||
const message = `anonymous-url edge case ${displayName}`;
|
||
await channelsPage.postMessage(message);
|
||
|
||
// * Verify the channel keeps the exact display name and remains usable
|
||
const lastPost = await channelsPage.getLastPost();
|
||
await expect(lastPost.body).toContainText(message);
|
||
await channelsPage.centerView.header.toHaveTitle(displayName);
|
||
await expect(channelsPage.page).toHaveURL(new RegExp(`/${team.name}/channels/${channel.name}$`));
|
||
}
|
||
|
||
const searchableChannel = createdChannels[1];
|
||
|
||
// # Reopen the channel from Find Channels using its display name
|
||
await channelsPage.goto(team.name, 'town-square');
|
||
await channelsPage.toBeVisible();
|
||
await channelsPage.sidebarLeft.findChannelButton.click();
|
||
await channelsPage.findChannelsModal.toBeVisible();
|
||
await channelsPage.findChannelsModal.input.fill(searchableChannel.displayName);
|
||
|
||
// * Verify search results use the display name and navigate back to the obfuscated slug
|
||
await expect(channelsPage.findChannelsModal.getResult(searchableChannel.channel.name)).toBeVisible();
|
||
await channelsPage.findChannelsModal.selectChannel(searchableChannel.channel.name);
|
||
await channelsPage.centerView.header.toHaveTitle(searchableChannel.displayName);
|
||
await expect(channelsPage.page).toHaveURL(
|
||
new RegExp(`/${team.name}/channels/${searchableChannel.channel.name}$`),
|
||
);
|
||
},
|
||
);
|
||
|
||
/**
|
||
* @objective Verify that anonymous URL channels with special-character names still expose the Calls entry point after direct navigation.
|
||
*
|
||
* @precondition
|
||
* Calls plugin must be installed in the test environment.
|
||
*/
|
||
test(
|
||
'shows calls entry point in anonymous URL channels with special-character names and preserves the obfuscated route',
|
||
{tag: '@anonymous_urls'},
|
||
async ({pw}) => {
|
||
// # Initialize setup and validate Calls prerequisites
|
||
const {adminUser, adminClient, team, user} = await pw.initSetup({withDefaultProfileImage: false});
|
||
await skipIfNoAdvancedLicense(adminClient);
|
||
|
||
const pluginStatuses = await adminClient.getPluginStatuses();
|
||
test.skip(
|
||
!pluginStatuses.some((plugin: {plugin_id: string}) => plugin.plugin_id === 'com.mattermost.calls'),
|
||
'Skipping test - Calls plugin is not installed',
|
||
);
|
||
|
||
await pw.ensurePluginsLoaded(['com.mattermost.calls']);
|
||
await pw.shouldHaveCallsEnabled();
|
||
await setAnonymousUrls(adminClient, true);
|
||
await adminClient.addToTeam(team.id, adminUser.id);
|
||
|
||
// # Create an anonymous URL channel with a special-character display name
|
||
const {channelsPage} = await pw.testBrowser.login(user);
|
||
await channelsPage.goto();
|
||
await channelsPage.toBeVisible();
|
||
|
||
const displayName = `Calls & Planning 🚀 ${pw.random.id().slice(0, 6)}`;
|
||
const channel = await createAnonymousUrlChannel(channelsPage, adminClient, team.name, team.id, displayName);
|
||
await adminClient.addToChannel(adminUser.id, channel.id);
|
||
|
||
// * Verify the current anonymous URL channel shows the Calls entry point
|
||
await channelsPage.centerView.header.toHaveTitle(displayName);
|
||
await expect(channelsPage.centerView.header.callButton).toBeVisible();
|
||
|
||
// # Open the anonymous URL directly as another member
|
||
const {channelsPage: otherChannelsPage} = await pw.testBrowser.login(adminUser);
|
||
await otherChannelsPage.goto(team.name, channel.name);
|
||
await otherChannelsPage.toBeVisible();
|
||
|
||
// * Verify direct navigation keeps the obfuscated slug and still exposes Calls
|
||
await otherChannelsPage.centerView.header.toHaveTitle(displayName);
|
||
await expect(otherChannelsPage.page).toHaveURL(new RegExp(`/${team.name}/channels/${channel.name}$`));
|
||
await expect(otherChannelsPage.centerView.header.callButton).toBeVisible();
|
||
|
||
// # Open the Calls entry point from the anonymous URL channel
|
||
await otherChannelsPage.centerView.header.openCalls();
|
||
|
||
// * Verify opening Calls does not break the anonymous URL route context
|
||
await otherChannelsPage.centerView.header.toHaveTitle(displayName);
|
||
await expect(otherChannelsPage.page).toHaveURL(new RegExp(`/${team.name}/channels/${channel.name}`));
|
||
},
|
||
);
|
||
});
|