* ci: shard server Postgres tests into 4 parallel runners (#35739) Cherry-pick of00296f9b49from master. * updated go to version 1.25.8 (#35817) Cherry-pick of32a10bac62from master. * Move password hashers from server/v8 to server/public (#35805) Cherry-pick ofcca3f08574from master. * Generate instead of hard-coding test passwords, enforce new minimum for FIPS, shard CI, fix FIPS builds (#35905) Cherry-pick of1bdd985b41from master. * upgrade golangci-lint (#35845) Cherry-pick of157e0400b2from master. On release-11.4 (unlike 11.5), UpdatePostsChannelTypeByChannelId and BackfillPostsChannelType exist in the elasticsearch/opensearch files, so the imports they require (fmt, updatebyquery, scriptlanguage) must be added — they were not in the cherry-pick diff since they already existed on master. Also updates html2text/tablewriter/olekukonko deps to fix a workspace conflict where enterprise's Go 1.25.8 bump pulled in a newer html2text that requires tablewriter ≥ 1.1 (was pinned to 0.0.5 via a replace directive). Matches the subset of866f759e4b(Mm 66662 bump deps) relevant to this incompatibility. * Fix FIPS-incompatible passwords and config in e2e test suites (#36001) Cherry-pick ofb51b4a8937from master. release-11.4 differences vs release-11.5: - demo_plugin_installation.spec.ts also deleted (modify/delete conflict, git rm) - authentication_2_spec.ts conflict: HEAD missing check() call; took incoming (check + FIPS-length passwords) - member_invitation_ui_spec.ts: HEAD has 'Create Account' (capital A) matching release-11.4 button text; kept HEAD's button text with incoming's newTestPassword() * fix(cypress): demo plugin (#36056) Cherry-pick of39f1979aa5from master. demo_plugin_installation.spec.ts was deleted in step 10 (modify/delete); re-created here with both the FIPS-password change and the URL fix. * test: clean up channel store data after TestChannelStore (#36066) TestChannelStore sub-tests create channels, members, and team members using fake TeamIds and UserIds (model.NewId() for non-existent rows). These records are left in the database and cause integrity tests (TestCheck*) running in the same binary to fail their full-table scans. Register a t.Cleanup on TestChannelStore that purges the affected tables entirely. A blanket purge is safe: the schema enforces no FK constraints, and every test suite creates its own data independently. * Fix command injection in server-test-template workflow (#36080) Cherry-pick of9223935f16from master. * fix(ci): restore testname format in sharded gotestsum runs (#36078) run-shard-tests.sh called gotestsum directly without --format, so it fell back to gotestsum's default (pkgname) instead of the testname format set by the Makefile. Pass --format "${GOTESTSUM_FORMAT:-testname}" to match the Makefile default. Co-authored-by: Mattermost Build <[email protected]> * fixup: drop demo_plugin playwright specs — master-only APIs demo_plugin/helpers.ts and demo_plugin_installation.spec.ts use installAndEnablePlugin and isPluginActive which don't exist on release-11.4's PlaywrightExtended type. These files were re-created by the step-11 cherry-pick of39f1979aa5, but they don't compile on this branch (same class of problem as actions.spec.ts in step 10). * fixup: add missing await in PluginLinkTooltip test The test added in39f1979aa5is missing an await on renderWithContext, causing the pointer-events assertion to race. Fix from 0c7d3f27c6 (on a feature branch, not yet on master). * fixup: drop pointer-events test incompatible with jsdom@20 The 'should not block interaction with elements outside the tooltip' test checks getComputedStyle for pointer-events: none, which is set only in SCSS. release-11.4 uses jest-environment-jsdom@29 (jsdom@20), which does not apply stylesheets, so getComputedStyle always returns "". The test passes on release-11.5+ only because they use jest-environment-jsdom@30 (jsdom@25+). Drop the test rather than backport the jsdom upgrade. * fixup: add missing i18n keys for elasticsearch/opensearch functions BackfillPostsChannelType and UpdatePostsChannelTypeByChannelId exist on release-11.4 (unlike release-11.5+). The golangci-lint cherry-pick added new error strings to those functions referencing i18n keys that weren't in en.json. * fixup: run make i18n-extract to reorder keys correctly * fixup: drop terms-and-privacy checkbox from MM-T1774 on release-11.4 The #signup-body-card-form-check-terms-and-privacy element did not exist on release-11.4's signup page. It was added to master after this branch was cut, so the check() call from the incoming cherry-pick causes the test to fail with "element never found". * fixup: remove UpdatePostsChannelTypeByChannelId/BackfillPostsChannelType These functions were introduced by MM-67540 (allow searching public channel messages without channel membership), which never landed on release-11.4. The golangci-lint cherry-pick only modernizes existing code; the rerere resolution incorrectly added the full function bodies from master. Remove both functions and their now-unused imports (fmt, updatebyquery, scriptlanguage) from elasticsearch.go and opensearch.go. Also remove the two i18n keys added to support them. Same treatment as release-11.5, where these functions were also absent. --------- Co-authored-by: Mattermost Build <[email protected]>
Local development
1. Start local server in a separate terminal.
There are two ways to run the local server:
Option 1: Run from source
# Typically run the local server with:
cd server && make run
# Or run webapp and server on separate terminals for better performance
# First terminal: Build and run the webapp
cd webapp && make run
# Second terminal: Run the server
cd server && make run-server
Option 2: Run using Docker (recommended for testing)
# 1. Configure environment variables in e2e-tests/.ci/env
# Create this file if it doesn't exist
# 2. Set the server image (optional)
# To use the latest master image:
SERVER_IMAGE="mattermostdevelopment/mattermost-enterprise-edition:master"
# If not set, it will use the current commit: mattermostdevelopment/mattermost-enterprise-edition:$(git rev-parse --short=7 HEAD)
# Note: The image must exist in Docker Hub at https://hub.docker.com/r/mattermostdevelopment/mattermost-enterprise-edition/tags
# 3. Add your license if needed
MM_LICENSE=<your-license-key>
# 4. For additional configuration options, see e2e-tests/README.md
# 5. Run the server and Playwright's smoke tests from the e2e-tests directory
cd e2e-tests && TEST=playwright make
This approach uses the server's Docker image to create a consistent testing environment. It automatically configures the server with the necessary settings for Playwright tests and handles dependencies.
2. Install dependencies and run the test.
# Install npm packages
npm i
# Install browser binaries as prompted if Playwright is just installed or updated
# See https://playwright.dev/docs/browsers
npx playwright install
# Run a specific test of all projects -- Chrome, Firefox, iPhone and iPad.
# See https://playwright.dev/docs/test-cli.
npm run test -- login
# Run a specific test of a project
npm run test -- login --project=chrome
# Run all tests (including visual tests)
npm run test
# Run CI tests (excludes visual tests, runs only in Chrome)
# Note: visual tests run in a separate workflow
npm run test:ci
3. Inspect test results at /results/output folder when something fails unexpectedly.
Run tests in UI mode
Check out https://playwright.dev/docs/test-ui-mode for detailed guide on UI Mode to learn more about its features.
npm run playwright-ui
Note: If no tests appear in the UI, check your filter settings:
- Test name filters
- Project filters (setup, ipad, chrome, firefox)
- Tag filters (@tag)
- Execution status filters
The "setup" project runs the initial configuration tests in
specs/test_setup.ts(ensuring plugins are loaded and server deployment is correct). These setup tests are typically run only once before other tests and may be unchecked for subsequent runs, though they can remain checked if needed.
Visual Testing
All visual tests must be placed in the specs/visual/ directory and tagged with @visual in the test tags array. This organization ensures proper test discovery and execution patterns.
Visual tests are used to verify the UI appearance is consistent across browsers and remains stable across code changes. There are two types of visual tests supported:
- Built-in snapshot testing: Uses Playwright's built-in snapshot comparison
- Percy integration: Uses the Percy service for more advanced visual testing and reporting
CI Pipeline for Visual Tests
In CI environments, visual tests run in a separate dedicated pipeline:
- Regular tests run with
npm run test:ciwhich excludes all tests with the@visualtag - Visual tests run in a separate workflow using the Playwright Docker container
- This separation prevents visual tests from slowing down the main test pipeline
- It also ensures visual tests always run in a consistent environment
Writing Visual Tests
When creating visual tests:
-
Follow the test documentation format like other tests:
- Include JSDoc with
@objectivetag - Use action-oriented test title
- Add proper comment prefixes (
// #for actions,// *for verifications)
- Include JSDoc with
-
Place in the correct location:
- Put visual tests in the
specs/visual/directory, organized by feature area - Example:
specs/visual/channels/intro_channel.spec.ts
- Put visual tests in the
-
Add required tags:
- Always include
@visualtag - Add feature-specific tags as needed (e.g.,
@login_page,@channel_page)
- Always include
-
Manage dynamic content:
- Use
pw.hideDynamicChannelsContent()to hide elements that could change between runs - Take snapshots only after UI is fully loaded and stable
- Use
Example:
/**
* @objective Capture visual snapshot of the landing/login page
*/
test(
'displays landing page with login options',
{tag: ['@visual', '@landing_page']},
async ({pw, page, browserName, viewport}, testInfo) => {
// # Go to landing login page
await pw.landingLoginPage.goto();
await pw.landingLoginPage.toBeVisible();
// * Verify landing page appears as expected
await pw.matchSnapshot(testInfo, {page, browserName, viewport});
},
);
Updating screenshots is done strictly via Playwright's docker container for consistency
1. Run Playwright's docker container
Change to the ./ project directory, then run the docker container. (See https://playwright.dev/docs/docker for reference.)
docker run -it --rm -v "$(pwd):/mattermost/" --ipc=host mcr.microsoft.com/playwright:v1.57.0-noble /bin/bash
2. Inside the docker container
export PW_BASE_URL=http://host.docker.internal:8065
export PW_HEADLESS=true
cd mattermost/e2e-tests/playwright
# Install npm packages. Use "npm ci" to match the automated environment
export PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1 npm ci
# Run specific test. See https://playwright.dev/docs/test-cli.
npm run test -- login --project=chrome
# Or run all tests
npm run test
# Run visual tests (must be run inside Docker for consistency)
npm run test -- specs/visual
# Update snapshots of visual tests (must be run inside Docker)
npm run test -- specs/visual --update-snapshots
# Run Percy visual tests (requires PERCY_TOKEN environment variable)
export PERCY_TOKEN=<your-percy-token>
npm run percy:docker
Accessibility Testing
Accessibility tests ensure Mattermost meets WCAG 2.1 AA compliance standards. Tests are located in specs/accessibility/ and cover keyboard navigation, screen reader support, focus management, and automated accessibility scanning.
For comprehensive guidelines on writing accessibility tests, aria snapshots, and folder structure, see docs/accessibility/.
Accessibility Locators
Playwright's accessibility locators should be the preferred approach for all tests, not just accessibility tests. These locators query elements based on how users and assistive technologies perceive them, making tests more resilient to implementation changes and ensuring better accessibility by design.
Why Use Accessibility Locators?
- Resilient to changes: Tests won't break when CSS classes or data-testid attributes change
- Encourages accessibility: Forces proper ARIA roles, labels, and semantic HTML
- Better readability:
page.getByRole('button', {name: 'Save'})is clearer thanpage.locator('[data-testid="save-btn"]') - Aligns with user experience: Tests what users actually perceive, not implementation details
Preferred Locators (in order of preference)
- Role-based:
page.getByRole('button', {name: 'Save'}),page.getByRole('textbox', {name: 'Email'}) - Label-based:
page.getByLabel('Email address') - Text-based:
page.getByText('Welcome'),page.getByPlaceholder('Enter email') - Test IDs:
page.locator('[data-testid="..."]')- Use only when accessibility locators aren't possible - CSS selectors:
page.locator('.class')- Avoid unless absolutely necessary
When Test IDs Are Acceptable
Use data-testid only when:
- Element has no semantic role (e.g., decorative divs)
- Multiple identical elements need distinction
- Component is not interactive or visible to assistive tech
For all test examples, see docs/accessibility/ for comprehensive patterns and best practices.
Page/Component Object Model
See https://playwright.dev/docs/test-pom.
Page and component abstractions are in shared library located at ./lib/src/ui. They should be established before writing a spec file so that any future changes in the DOM structure will be made in one place only. No static UI text or fixed locator should be written in the spec file.