Files
upstream-mattermost/e2e-tests/playwright/specs/functional/channels/mobile_logs_command.spec.ts
upstream-mirror 240db4e2a7
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 Cache Warm / Warm Go Module and Build Cache (push) Failing after 2s
Server CI Nightly Race / Build Environment (push) Failing after 1s
snapshot of https://github.com/mattermost/mattermost.git (master, 2026-09-16; blobs > 131072B omitted)
2026-09-16 00:29:55 +05:00

322 lines
13 KiB
TypeScript

// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {expect, test} from '@mattermost/playwright-lib';
/**
* Helper to find the attach_app_logs preference for a given user.
*/
async function getAttachLogsPreference(
userClient: {
getUserPreferences: (userId: string) => Promise<Array<{category: string; name: string; value: string}>>;
},
userId: string,
) {
const prefs = await userClient.getUserPreferences(userId);
return prefs.find(
(p: {category: string; name: string}) => p.category === 'advanced_settings' && p.name === 'attach_app_logs',
);
}
test.describe('/mobile-logs slash command', () => {
/**
* @objective Verify that /mobile-logs on sets the attach_app_logs preference to true
* and returns an ephemeral confirmation visible only to the invoking user.
*/
test(
'MM-T67880 enables mobile logs for self and confirms preference is set',
{tag: '@slash_commands'},
async ({pw}) => {
// # Initialize setup
const {team, user, userClient} = await pw.initSetup();
// # Log in as the user and navigate to town-square
const {channelsPage} = await pw.testBrowser.login(user);
await channelsPage.goto(team.name, 'town-square');
await channelsPage.toBeVisible();
// # Execute /mobile-logs on
await channelsPage.postMessage('/mobile-logs on');
// * Verify ephemeral response confirms logs enabled
const lastPost = await channelsPage.getLastPost();
await lastPost.toContainText('Mobile app log attachment is now enabled for you');
// * Verify the response is ephemeral (only visible to the user)
await expect(lastPost.container.locator('.post__visibility')).toContainText('(Only visible to you)');
// * Verify the preference was actually set via API
const logPref = await getAttachLogsPreference(userClient, user.id);
expect(logPref).toBeDefined();
expect(logPref!.value).toBe('true');
},
);
/**
* @objective Verify that /mobile-logs off sets the attach_app_logs preference to false
* and returns an ephemeral confirmation.
*/
test('MM-T67880 disables mobile logs for self after enabling via API', {tag: '@slash_commands'}, async ({pw}) => {
// # Initialize setup
const {team, user, userClient} = await pw.initSetup();
// # Pre-enable the preference via API to avoid back-to-back commands
await userClient.savePreferences(user.id, [
{user_id: user.id, category: 'advanced_settings', name: 'attach_app_logs', value: 'true'},
]);
// # Log in as the user and navigate to town-square
const {channelsPage} = await pw.testBrowser.login(user);
await channelsPage.goto(team.name, 'town-square');
await channelsPage.toBeVisible();
// # Execute /mobile-logs off
await channelsPage.postMessage('/mobile-logs off');
// * Verify ephemeral response confirms logs disabled
const lastPost = await channelsPage.getLastPost();
await lastPost.toContainText('Mobile app log attachment is now disabled for you');
// * Verify the preference was set to false via API
const logPref = await getAttachLogsPreference(userClient, user.id);
expect(logPref).toBeDefined();
expect(logPref!.value).toBe('false');
});
/**
* @objective Verify that /mobile-logs status reports disabled by default for a fresh user.
*/
test(
'MM-T67880 reports mobile logs status as disabled for a fresh user',
{tag: '@slash_commands'},
async ({pw}) => {
// # Initialize setup
const {team, user} = await pw.initSetup();
// # Log in as the user and navigate to town-square
const {channelsPage} = await pw.testBrowser.login(user);
await channelsPage.goto(team.name, 'town-square');
await channelsPage.toBeVisible();
// # Execute /mobile-logs status
await channelsPage.postMessage('/mobile-logs status');
// * Verify ephemeral response shows disabled
const lastPost = await channelsPage.getLastPost();
await lastPost.toContainText('Mobile app log attachment is currently disabled for you');
},
);
/**
* @objective Verify that /mobile-logs status reports enabled after the preference
* has been set to true via API.
*/
test(
'MM-T67880 reports mobile logs status as enabled after preference is set',
{tag: '@slash_commands'},
async ({pw}) => {
// # Initialize setup
const {team, user, userClient} = await pw.initSetup();
// # Pre-enable the preference via API
await userClient.savePreferences(user.id, [
{user_id: user.id, category: 'advanced_settings', name: 'attach_app_logs', value: 'true'},
]);
// # Log in as the user and navigate to town-square
const {channelsPage} = await pw.testBrowser.login(user);
await channelsPage.goto(team.name, 'town-square');
await channelsPage.toBeVisible();
// # Execute /mobile-logs status
await channelsPage.postMessage('/mobile-logs status');
// * Verify ephemeral response shows enabled
const lastPost = await channelsPage.getLastPost();
await lastPost.toContainText('Mobile app log attachment is currently enabled for you');
},
);
/**
* @objective Verify that /mobile-logs displays a usage hint when invoked
* without arguments or with an invalid action.
*/
test('MM-T67880 displays usage hint for invalid or missing arguments', {tag: '@slash_commands'}, async ({pw}) => {
// # Initialize setup
const {team, user} = await pw.initSetup();
// # Log in as the user and navigate to town-square
const {channelsPage} = await pw.testBrowser.login(user);
await channelsPage.goto(team.name, 'town-square');
await channelsPage.toBeVisible();
// # Execute /mobile-logs with an invalid action
await channelsPage.postMessage('/mobile-logs invalid');
// * Verify usage message is shown
const lastPost = await channelsPage.getLastPost();
await lastPost.toContainText('Usage: /mobile-logs [on|off|status] [@username]');
});
/**
* @objective Verify that a system admin can enable mobile logs for another user
* and the preference is persisted on the target user's account.
*/
test(
'MM-T67880 admin enables mobile logs for another user and preference is persisted',
{tag: '@slash_commands'},
async ({pw}) => {
// # Initialize setup
const {team, adminUser, user, userClient} = await pw.initSetup();
// # Log in as admin and navigate to town-square
const {channelsPage} = await pw.testBrowser.login(adminUser);
await channelsPage.goto(team.name, 'town-square');
await channelsPage.toBeVisible();
// # Execute /mobile-logs on for the regular user
await channelsPage.postMessage(`/mobile-logs on @${user.username}`);
// * Verify ephemeral response confirms logs enabled for the target user
const lastPost = await channelsPage.getLastPost();
await lastPost.toContainText(`Mobile app log attachment is now enabled for @${user.username}`);
// * Verify the preference was set on the target user via API
const logPref = await getAttachLogsPreference(userClient, user.id);
expect(logPref).toBeDefined();
expect(logPref!.value).toBe('true');
},
);
/**
* @objective Verify that a system admin can disable mobile logs for another user
* after they have been enabled.
*/
test(
'MM-T67880 admin disables mobile logs for another user after enabling via API',
{tag: '@slash_commands'},
async ({pw}) => {
// # Initialize setup
const {team, adminUser, user, userClient} = await pw.initSetup();
// # Pre-enable the preference for the target user via API
const {adminClient} = await pw.getAdminClient();
await adminClient.savePreferences(user.id, [
{user_id: user.id, category: 'advanced_settings', name: 'attach_app_logs', value: 'true'},
]);
// # Log in as admin and navigate to town-square
const {channelsPage} = await pw.testBrowser.login(adminUser);
await channelsPage.goto(team.name, 'town-square');
await channelsPage.toBeVisible();
// # Disable for the regular user
await channelsPage.postMessage(`/mobile-logs off @${user.username}`);
// * Verify ephemeral response confirms logs disabled
const lastPost = await channelsPage.getLastPost();
await lastPost.toContainText(`Mobile app log attachment is now disabled for @${user.username}`);
// * Verify the preference was set to false on the target user
const logPref = await getAttachLogsPreference(userClient, user.id);
expect(logPref).toBeDefined();
expect(logPref!.value).toBe('false');
},
);
/**
* @objective Verify that a non-admin user is denied when attempting to modify
* another user's mobile logs preference.
*/
test(
'MM-T67880 rejects mobile log modification when caller is not an admin',
{tag: '@slash_commands'},
async ({pw}) => {
// # Initialize setup with two regular users
const {team, adminClient, user} = await pw.initSetup();
const otherUser = await pw.random.user('other');
const {id: otherUserId} = await adminClient.createUser(otherUser, '', '');
await adminClient.addToTeam(team.id, otherUserId);
// # Log in as the first regular user
const {channelsPage} = await pw.testBrowser.login(user);
await channelsPage.goto(team.name, 'town-square');
await channelsPage.toBeVisible();
// # Try to enable mobile logs for the other user
await channelsPage.postMessage(`/mobile-logs on @${otherUser.username}`);
// * Verify permission denied message
const lastPost = await channelsPage.getLastPost();
await lastPost.toContainText('Unable to change mobile log settings for that user.');
},
);
/**
* @objective Verify that a regular user cannot infer whether a username exists when
* attempting to target another account (same denial as missing permission).
*/
test(
'MM-T67880 regular user gets permission denial for nonexistent cross-user target',
{tag: '@slash_commands'},
async ({pw}) => {
const {team, user} = await pw.initSetup();
const {channelsPage} = await pw.testBrowser.login(user);
await channelsPage.goto(team.name, 'town-square');
await channelsPage.toBeVisible();
// # Post the mobile-logs command
await channelsPage.postMessage('/mobile-logs on @nonexistentuser12345');
const lastPost = await channelsPage.getLastPost();
// * Expect permission denial message
await lastPost.toContainText('Unable to change mobile log settings for that user.');
},
);
/**
* @objective Verify that a system admin can check the mobile logs status for another
* user and it correctly reflects the current preference state.
*/
test('MM-T67880 admin checks mobile logs status for another user', {tag: '@slash_commands'}, async ({pw}) => {
// # Initialize setup
const {team, adminUser, user} = await pw.initSetup();
// # Log in as admin and navigate to town-square
const {channelsPage} = await pw.testBrowser.login(adminUser);
await channelsPage.goto(team.name, 'town-square');
await channelsPage.toBeVisible();
// # Check status (default off)
await channelsPage.postMessage(`/mobile-logs status @${user.username}`);
// * Verify status shows disabled
const statusOffPost = await channelsPage.getLastPost();
await statusOffPost.toContainText(`Mobile app log attachment is currently disabled for @${user.username}`);
});
/**
* @objective Verify that /mobile-logs returns a user-not-found error when targeting
* a nonexistent username.
*/
test('MM-T67880 returns error for nonexistent target user', {tag: '@slash_commands'}, async ({pw}) => {
// # Initialize setup
const {team, adminUser} = await pw.initSetup();
// # Log in as admin
const {channelsPage} = await pw.testBrowser.login(adminUser);
await channelsPage.goto(team.name, 'town-square');
await channelsPage.toBeVisible();
// # Try to enable for a nonexistent user
await channelsPage.postMessage('/mobile-logs on @nonexistentuser12345');
// * Verify user not found message — wait up to 30 s for the slash command response post
await expect(channelsPage.centerView.container).toContainText('Could not find user "nonexistentuser12345"', {
timeout: 30000,
});
});
});