mattermost-mobile-upstream/app/screens/watermark/index.test.tsx
Elias Nahum b6fc85385e
Migrate from RNN to Expo router (#9402)
* Expo-Router partial migration

* Full migration to ExpoRouter

* i18n

* add tests

* Merge branch 'main' into expo-router

* align package-lock.json

* i18n

* feedback review

* feedback review

* android 16kb patch

* Refactored emoji picker keyboard using a state machine

* set android launch_screen in drawables instead of layout

* no conditional hooks

* remove duplicate call in test

* address feedback

* fix tests and address more feedback

* small corrections

* small corrections

* small corrections

* fix draft test

* fix draft test 2

* remove navigateToScreen in draff test

* fix nit in draft test

* remove doc file

* Feedback review

* fix snapshots

* improve test coverage

* fix i18n

* Upgrade t o RN 0.83, other dependencies and new architecture (#9737)

* library hardware-keyboard android new arch support fix

* library rnshare android new arch support fix

* library rnutils android new arch support fix

* library secure-pdf-viewer add new arch support

* Enable new arch on iOS and Android

* update emm and network client with new-arch

* update intune to use new-arch

* performance improvements

* fix tests

* fixes post input on new-arch

* fix android emoji picker

* remove doc

* run tests in parallel

* upgrade to React Native 0.83.9, Expo 55, React 19, and New Architecture

Bumps core dependencies to their latest versions:
- React Native 0.77.3 → 0.83.9 (New Architecture enabled)
- React 18.3.1 → 19.2.5
- Expo SDK 52 → 55
- TypeScript 5.8.3 → 6.0.3
- Node.js 22.16.0 → 24.15.0
- react-native-reanimated 3.17.3 → 4.3.0
- Various other dependency upgrades

Migrates iOS AppDelegate from Objective-C to Swift, updates Android
build tooling and Gradle wrapper, refreshes all patches and font
assets, and adapts app code, tests, and CI workflows throughout for
API changes introduced by these upgrades.

* remove unecessary dismissKeyboard in notifications

* feedback review

* update intune to use new-arch

* update @mattermost deps

* missing i18n string

* additional fixes

* update fastlane
2026-05-13 17:44:55 +08:00

150 lines
5.7 KiB
TypeScript

// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import DatabaseManager from '@database/manager';
import {renderWithEverything, waitFor} from '@test/intl-test-helper';
import TestHelper from '@test/test_helper';
import WatermarkScreenExport from './index';
import type {Database} from '@nozbe/watermelondb';
// Portal renders children into a named host declared in _layout.tsx.
// In unit tests there is no host, so we render children directly.
jest.mock('@gorhom/portal', () => {
const React = require('react');
const {View} = require('react-native');
return {
Portal: ({children}: {children: React.ReactNode}) => React.createElement(View, {testID: 'portal'}, children),
};
});
// FullWindowOverlay is a native component — render children passthrough in tests.
jest.mock('react-native-screens', () => {
const React = require('react');
return {
FullWindowOverlay: ({children}: {children: React.ReactNode}) => React.createElement(React.Fragment, null, children),
};
});
describe('WatermarkScreen', () => {
let database: Database;
const serverUrl = 'http://www.someserver.com';
beforeAll(async () => {
const server = await TestHelper.setupServerDatabase(serverUrl);
await DatabaseManager.updateServerIdentifier(serverUrl, 'someidentifier');
await DatabaseManager.setActiveServerDatabase(serverUrl);
database = server.database;
});
afterAll(() => {
DatabaseManager.destroyServerDatabase(serverUrl);
});
it('should render nothing when watermark is disabled', async () => {
const {queryByTestId} = renderWithEverything(
<WatermarkScreenExport/>,
{database, serverUrl},
);
// Give observables time to resolve — the portal should never appear.
await waitFor(() => {
expect(queryByTestId('portal')).toBeNull();
});
});
it('should render watermark text containing username and server URL when enabled', async () => {
// Enable the watermark via the system config in the DB.
const {operator} = DatabaseManager.getServerDatabaseAndOperator(serverUrl);
await operator.handleConfigs({
configs: [{id: 'ExperimentalEnableWatermark', value: 'true'}],
configsToDelete: [],
prepareRecordsOnly: false,
});
const {getAllByText, unmount} = renderWithEverything(
<WatermarkScreenExport/>,
{database, serverUrl},
);
// The watermark container is hidden from accessibility intentionally;
// use includeHiddenElements to still find the text in tests.
await waitFor(() => {
expect(getAllByText(/www\.someserver\.com/, {includeHiddenElements: true}).length).toBeGreaterThan(0);
});
// Unmount before resetting config to avoid act() warnings from post-unmount observable updates.
unmount();
await operator.handleConfigs({
configs: [{id: 'ExperimentalEnableWatermark', value: 'false'}],
configsToDelete: [],
prepareRecordsOnly: false,
});
});
it('should render multiple copies of the watermark text for the tiled grid pattern when enabled', async () => {
const {operator} = DatabaseManager.getServerDatabaseAndOperator(serverUrl);
await operator.handleConfigs({
configs: [{id: 'ExperimentalEnableWatermark', value: 'true'}],
configsToDelete: [],
prepareRecordsOnly: false,
});
const {getAllByText, unmount} = renderWithEverything(
<WatermarkScreenExport/>,
{database, serverUrl},
);
await waitFor(() => {
expect(getAllByText(/www\.someserver\.com/, {includeHiddenElements: true}).length).toBeGreaterThan(1);
});
unmount();
await operator.handleConfigs({
configs: [{id: 'ExperimentalEnableWatermark', value: 'false'}],
configsToDelete: [],
prepareRecordsOnly: false,
});
});
it('should render watermark text with username, server URL, date and time when enabled', async () => {
const {operator} = DatabaseManager.getServerDatabaseAndOperator(serverUrl);
await operator.handleConfigs({
configs: [{id: 'ExperimentalEnableWatermark', value: 'true'}],
configsToDelete: [],
prepareRecordsOnly: false,
});
// Freeze Date so the watermark's "now" is deterministic.
// Only fake Date — keep all timer APIs real so WatermelonDB observables resolve normally.
jest.useFakeTimers({
now: new Date('2026-04-14T10:30:00'),
doNotFake: ['nextTick', 'setImmediate', 'clearImmediate', 'setInterval', 'clearInterval', 'setTimeout', 'clearTimeout', 'queueMicrotask'],
});
let unmount: () => void;
try {
const username = TestHelper.basicUser!.username;
const rendered = renderWithEverything(
<WatermarkScreenExport/>,
{database, serverUrl},
);
unmount = rendered.unmount;
const expectedText = `${username} ${serverUrl} 4/14/2026 10:30 AM`;
await waitFor(() => {
expect(rendered.getAllByText(expectedText, {includeHiddenElements: true}).length).toBeGreaterThan(0);
});
} finally {
unmount!();
jest.useRealTimers();
await operator.handleConfigs({
configs: [{id: 'ExperimentalEnableWatermark', value: 'false'}],
configsToDelete: [],
prepareRecordsOnly: false,
});
}
});
});