diff --git a/webapp/channels/src/components/admin_console/__snapshots__/database_settings.test.tsx.snap b/webapp/channels/src/components/admin_console/__snapshots__/database_settings.test.tsx.snap index a9800880415..08a37e8882e 100644 --- a/webapp/channels/src/components/admin_console/__snapshots__/database_settings.test.tsx.snap +++ b/webapp/channels/src/components/admin_console/__snapshots__/database_settings.test.tsx.snap @@ -1,420 +1,493 @@ // Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing exports[`components/DatabaseSettings should match snapshot 1`] = ` -
-
+ - - - - +
- + Database
-
- -
-
-
- -
-
- + +
+ +
+ Set the database driver in the config.json file. +
+
-
-
- - } - id="maxIdleConns" - label={ - - } - onChange={[Function]} - placeholder={ - Object { - "defaultMessage": "E.g.: \\"10\\"", - "id": "admin.sql.maxConnectionsExample", - } - } - setByEnv={false} - type="text" - value={10} - /> - - } - id="maxOpenConns" - label={ - - } - onChange={[Function]} - placeholder={ - Object { - "defaultMessage": "E.g.: \\"10\\"", - "id": "admin.sql.maxOpenExample", - } - } - setByEnv={false} - type="text" - value={100} - /> - - } - id="queryTimeout" - label={ - - } - onChange={[Function]} - placeholder={ - Object { - "defaultMessage": "E.g.: \\"30\\"", - "id": "admin.sql.queryTimeoutExample", - } - } - setByEnv={false} - type="text" - value={10} - /> - - } - id="connMaxLifetimeMilliseconds" - label={ - - } - onChange={[Function]} - placeholder={ - Object { - "defaultMessage": "E.g.: \\"3600000\\"", - "id": "admin.sql.connMaxLifetimeExample", - } - } - setByEnv={false} - type="text" - value={10} - /> - - } - id="connMaxIdleTimeMilliseconds" - label={ - - } - onChange={[Function]} - placeholder={ - Object { - "defaultMessage": "E.g.: \\"300000\\"", - "id": "admin.sql.connMaxIdleTimeExample", - } - } - setByEnv={false} - type="text" - value={20} - /> - - } - id="minimumHashtagLength" - label={ - - } - onChange={[Function]} - placeholder={ - Object { - "defaultMessage": "E.g.: \\"3\\"", - "id": "admin.service.minimumHashtagLengthExample", - } - } - setByEnv={false} - type="text" - value={10} - /> - - } - id="trace" - label={ - - } - onChange={[Function]} - setByEnv={false} - value={false} - /> - - } - disabled={false} - errorMessage={ - Object { - "defaultMessage": "Recycling unsuccessful: {error}", - "id": "admin.recycle.reloadFail", - } - } - helpText={ - - - , - "reloadConfiguration": + +
+ +
+ Set the database source in the config.json file. +
+
+
+
+ +
+ +
+ Maximum number of idle connections held open to the database. +
+
+
+
+ +
+ +
+ Maximum number of open connections held open to the database. +
+
+
+
+ +
+ +
+ The number of seconds to wait for a response from the database after opening a connection and sending the query. Errors that you see in the UI or in the logs as a result of a query timeout can vary depending on the type of query. +
+
+
+
+ +
+ +
+ Maximum lifetime for a connection to the database in milliseconds. +
+
+
+
+ +
+ +
+ Maximum idle time for a connection to the database in milliseconds. +
+
+
+
+ +
+ +
+ Minimum number of characters in a hashtag. This must be greater than or equal to 2. +
+
+
+
+ + SQL Statement Logging: + +
+ + +
+ (Development Mode) When true, executing SQL statements are written to the log. +
+
+
+
+
+
+ +
+
+ Deployments using multiple databases can switch from one master database to another without restarting the Mattermost server by updating "config.json" to the new desired configuration and using the + - + Environment > Web Server > Reload Configuration from Disk - , - } - } - /> - } - includeDetailedError={true} - requestAction={[MockFunction]} - saveNeeded={false} - showSuccessMessage={false} - successMessage={ - Object { - "defaultMessage": "Test Successful", - "id": "admin.requestButton.requestSuccess", - } - } - /> - - } - id="disableDatabaseSearch" - label={ - - } - onChange={[Function]} - setByEnv={false} - value={true} - /> - - } - > -
- - } - /> -
-
-
- -
- -
+ feature to load the new settings while the server is running. The administrator should then use + + Recycle Database Connections + + feature to recycle the database connections based on the new settings. +
+
+
+
- + + Disable database search: + +
+ + +
+ Disables the use of the database to perform searches. Should only be used when other + + search engines + + are configured. +
+
+
+
+ + Schema Migrations: + +
+
+
+
+ All applied migrations. +
+
+ + + + + + + + +
+ Version + + Name +
+
+
+
+
+
+
+ +
+ +
+ Shows the currently active backend used for search. Values can be none, database, elasticsearch. +
+
- -
- - } - /> - -
- -
-
+ + Save + + +
+
-
- + +
`; diff --git a/webapp/channels/src/components/admin_console/__snapshots__/elasticsearch_settings.test.tsx.snap b/webapp/channels/src/components/admin_console/__snapshots__/elasticsearch_settings.test.tsx.snap index 488b15d485e..43ef5e9bb62 100644 --- a/webapp/channels/src/components/admin_console/__snapshots__/elasticsearch_settings.test.tsx.snap +++ b/webapp/channels/src/components/admin_console/__snapshots__/elasticsearch_settings.test.tsx.snap @@ -1,1024 +1,1493 @@ // Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing exports[`components/ElasticSearchSettings should match snapshot, disabled 1`] = ` -
-
+ - - - - - Learn more about Elasticsearch in our documentation." - id="admin.elasticsearch.enableIndexingDescription" - values={ - Object { - "link": [Function], - } - } - /> - } - id="enableIndexing" - label={ - - } - onChange={[Function]} - setByEnv={false} - value={false} - /> - - } - id="backend" - label={ - - } - onChange={[Function]} - placeholder={ - Object { - "defaultMessage": "E.g.: \\"elasticsearch\\"", - "id": "admin.elasticsearch.backendExample", - } - } - setByEnv={false} - /> - - } - id="connectionUrl" - label={ - - } - onChange={[Function]} - placeholder={ - Object { - "defaultMessage": "E.g.: \\"https://elasticsearch.example.org:9200\\"", - "id": "admin.elasticsearch.connectionUrlExample", - } - } - setByEnv={false} - value="test" - /> - - } - id="ca" - label={ - - } - onChange={[Function]} - placeholder={ - Object { - "defaultMessage": "E.g.: \\"./elasticsearch/ca.pem\\"", - "id": "admin.elasticsearch.caExample", - } - } - setByEnv={false} - value="test.ca" - /> - - } - id="clientCert" - label={ - - } - onChange={[Function]} - placeholder={ - Object { - "defaultMessage": "E.g.: \\"./elasticsearch/client-cert.pem\\"", - "id": "admin.elasticsearch.clientCertExample", - } - } - setByEnv={false} - value="test.crt" - /> - - } - id="clientKey" - label={ - - } - onChange={[Function]} - placeholder={ - Object { - "defaultMessage": "E.g.: \\"./elasticsearch/client-key.pem\\"", - "id": "admin.elasticsearch.clientKeyExample", - } - } - setByEnv={false} - value="test.key" - /> - - } - id="skipTLSVerification" - label={ - - } - onChange={[Function]} - setByEnv={false} - value={false} - /> - - } - id="username" - label={ - - } - onChange={[Function]} - placeholder={ - Object { - "defaultMessage": "E.g.: \\"elastic\\"", - "id": "admin.elasticsearch.usernameExample", - } - } - setByEnv={false} - value="test" - /> - - } - id="password" - label={ - - } - onChange={[Function]} - placeholder={ - Object { - "defaultMessage": "E.g.: \\"yourpassword\\"", - "id": "admin.elasticsearch.password", - } - } - setByEnv={false} - value="test" - /> - - } - id="sniff" - label={ - - } - onChange={[Function]} - setByEnv={false} - value={false} - /> - - } - disabled={true} - errorMessage={ - Object { - "defaultMessage": "Test Failure: {error}", - "id": "admin.requestButton.requestFailure", - } - } - helpText={ - - } - id="testConfig" - includeDetailedError={true} - requestAction={[Function]} - saveNeeded={false} - showSuccessMessage={true} - successMessage={ - Object { - "defaultMessage": "Test successful. Configuration saved.", - "id": "admin.elasticsearch.testConfigSuccess", - } - } - /> - - } - > -
- - } - createJobHelpText={ - - } - disabled={true} - getExtraInfoText={[Function]} - jobType="elasticsearch_post_indexing" - /> -
-
- - } - disabled={true} - errorMessage={ - Object { - "defaultMessage": "Failed to trigger channels index rebuild job: {error}", - "id": "admin.elasticsearch.rebuildIndexSuccessfully.error", - } - } - helpText={ - - } - id="rebuildChannelsIndexButton" - includeDetailedError={false} - label={ - - } - requestAction={[MockFunction]} - saveNeeded={false} - showSuccessMessage={true} - successMessage={ - Object { - "defaultMessage": "Channels index rebuild job triggered successfully.", - "id": "admin.elasticsearch.rebuildIndexSuccessfully.success", - } - } - /> - - } - disabled={true} - errorMessage={ - Object { - "defaultMessage": "Failed to purge indexes: {error}", - "id": "admin.elasticsearch.purgeIndexesButton.error", - } - } - helpText={ - - } - id="purgeIndexesSection" - includeDetailedError={false} - label={ - - } - requestAction={[MockFunction]} - saveNeeded={false} - showSuccessMessage={true} - successMessage={ - Object { - "defaultMessage": "Indexes purged successfully.", - "id": "admin.elasticsearch.purgeIndexesButton.success", - } - } - /> - - } - id="ignoredPurgeIndexes" - label={ - - } - onChange={[Function]} - placeholder={ - Object { - "defaultMessage": "E.g.: .opendistro*,.security*", - "id": "admin.elasticsearch.ignoredPurgeIndexesDescription.example", - } - } - setByEnv={false} - /> - - } - id="enableSearching" - label={ - - } - onChange={[Function]} - setByEnv={false} - value={false} - /> - - } - id="enableAutocomplete" - label={ - - } - onChange={[Function]} - setByEnv={false} - value={false} - /> - - } - id="enableSearchPublicChannelsWithoutMembership" - label={ - - } - onChange={[Function]} - setByEnv={false} - /> -
- - } - /> - + Elasticsearch +
+
- +
+ + Enable Elasticsearch Indexing: + +
+ + +
+ When true, indexing of new posts occurs automatically. Search queries will use database search until "Enable Elasticsearch for search queries" is enabled. + + Learn more about Elasticsearch in our documentation. + +
+
+
+
+ +
+ +
+ The type of the search backend. Changing this setting requires a server restart before taking effect. +
+
+
+
+ +
+ +
+ The address of the Elasticsearch server. + + Please see documentation with server setup instructions. + +
+
+
+
+ +
+ +
+ (Optional) Custom Certificate Authority certificates for the Elasticsearch server. Leave this empty to use the default CAs from the operating system. +
+
+
+
+ +
+ +
+ (Optional) The client certificate for the connection to the Elasticsearch server in the PEM format. +
+
+
+
+ +
+ +
+ (Optional) The key for the client certificate in the PEM format. +
+
+
+
+ + Skip TLS Verification: + +
+ + +
+ When true, Mattermost will not require the Elasticsearch certificate to be signed by a trusted Certificate Authority. +
+
+
+
+ +
+ +
+ (Optional) The username to authenticate to the Elasticsearch server. +
+
+
+
+ +
+ +
+ (Optional) The password to authenticate to the Elasticsearch server. +
+
+
+
+ + Enable Cluster Sniffing: + +
+ + +
+ When true, sniffing finds and connects to all data nodes in your cluster automatically. +
+
+
+
+
+
+ +
+
+ Tests if the Mattermost server can connect to the Elasticsearch server specified. Testing the connection only saves the configuration if the test is successful. A successful test will also re-initialize the client if you have started Elasticsearch after starting Mattermost. But this will not restart the workers. To do that, please toggle "Enable Elasticsearch Indexing". +
+
+
+
+ + Bulk Indexing: + +
+
+
+
+
+ +
+
+ All users, channels and posts in the database will be indexed from oldest to newest. Elasticsearch is available during indexing but search results may be incomplete until the indexing job is complete. +
+
+
+ + + + + + + + + + +
+ Status + + Finish Time + + Run Time + + Details + +
+
+
+
+
+
+
+ +
+
+ +
+
+ This purges the channels index and re-indexes all channels in the database, from oldest to newest. Channel autocomplete is available during indexing but search results may be incomplete until the indexing job is complete. + + + + Note- Please ensure no other indexing job is in progress in the table above. + +
+
+
+
+ +
+
+ +
+
+ Purging will entirely remove the indexes on the Elasticsearch server. Search results may be incomplete until a bulk index of the existing database is rebuilt. +
+
+
+
+ +
+ +
+ When filled in, these indexes will be ignored during the purge, separated by commas. +
+
+
+
+ + Enable Elasticsearch for search queries: + +
+ + +
+ Requires a successful connection to the Elasticsearch server. When true, Elasticsearch will be used for all search queries using the latest index. Search results may be incomplete until a bulk index of the existing post database is finished. When false, database search is used. +
+
+
+
+ + Enable Elasticsearch for autocomplete queries: + +
+ + +
+ Requires a successful connection to the Elasticsearch server. When true, Elasticsearch will be used for all autocompletion queries on users and channels using the latest index. Autocompletion results may be incomplete until a bulk index of the existing users and channels database is finished. When false, database autocomplete is used. +
+
+
+
+ + Allow searching public channels without membership: + +
+ + +
+ When enabled, users can find messages in public channels they have not joined. When enabled for the first time, existing posts will be updated in the background. This process is throttled to avoid impacting search performance. This setting has no effect when Compliance Mode is enabled. +
+
+
- +
+
+ +
+
-
-
+ + `; exports[`components/ElasticSearchSettings should match snapshot, enabled 1`] = ` -
-
+ - - - - - Learn more about Elasticsearch in our documentation." - id="admin.elasticsearch.enableIndexingDescription" - values={ - Object { - "link": [Function], - } - } - /> - } - id="enableIndexing" - label={ - - } - onChange={[Function]} - setByEnv={false} - value={true} - /> - - } - id="backend" - label={ - - } - onChange={[Function]} - placeholder={ - Object { - "defaultMessage": "E.g.: \\"elasticsearch\\"", - "id": "admin.elasticsearch.backendExample", - } - } - setByEnv={false} - /> - - } - id="connectionUrl" - label={ - - } - onChange={[Function]} - placeholder={ - Object { - "defaultMessage": "E.g.: \\"https://elasticsearch.example.org:9200\\"", - "id": "admin.elasticsearch.connectionUrlExample", - } - } - setByEnv={false} - value="test" - /> - - } - id="ca" - label={ - - } - onChange={[Function]} - placeholder={ - Object { - "defaultMessage": "E.g.: \\"./elasticsearch/ca.pem\\"", - "id": "admin.elasticsearch.caExample", - } - } - setByEnv={false} - value="test.ca" - /> - - } - id="clientCert" - label={ - - } - onChange={[Function]} - placeholder={ - Object { - "defaultMessage": "E.g.: \\"./elasticsearch/client-cert.pem\\"", - "id": "admin.elasticsearch.clientCertExample", - } - } - setByEnv={false} - value="test.crt" - /> - - } - id="clientKey" - label={ - - } - onChange={[Function]} - placeholder={ - Object { - "defaultMessage": "E.g.: \\"./elasticsearch/client-key.pem\\"", - "id": "admin.elasticsearch.clientKeyExample", - } - } - setByEnv={false} - value="test.key" - /> - - } - id="skipTLSVerification" - label={ - - } - onChange={[Function]} - setByEnv={false} - value={false} - /> - - } - id="username" - label={ - - } - onChange={[Function]} - placeholder={ - Object { - "defaultMessage": "E.g.: \\"elastic\\"", - "id": "admin.elasticsearch.usernameExample", - } - } - setByEnv={false} - value="test" - /> - - } - id="password" - label={ - - } - onChange={[Function]} - placeholder={ - Object { - "defaultMessage": "E.g.: \\"yourpassword\\"", - "id": "admin.elasticsearch.password", - } - } - setByEnv={false} - value="test" - /> - - } - id="sniff" - label={ - - } - onChange={[Function]} - setByEnv={false} - value={false} - /> - - } - disabled={false} - errorMessage={ - Object { - "defaultMessage": "Test Failure: {error}", - "id": "admin.requestButton.requestFailure", - } - } - helpText={ - - } - id="testConfig" - includeDetailedError={true} - requestAction={[Function]} - saveNeeded={false} - showSuccessMessage={true} - successMessage={ - Object { - "defaultMessage": "Test successful. Configuration saved.", - "id": "admin.elasticsearch.testConfigSuccess", - } - } - /> - - } - > -
- - } - createJobHelpText={ - - } - getExtraInfoText={[Function]} - jobType="elasticsearch_post_indexing" - /> -
-
- - } - disabled={false} - errorMessage={ - Object { - "defaultMessage": "Failed to trigger channels index rebuild job: {error}", - "id": "admin.elasticsearch.rebuildIndexSuccessfully.error", - } - } - helpText={ - - } - id="rebuildChannelsIndexButton" - includeDetailedError={false} - label={ - - } - requestAction={[MockFunction]} - saveNeeded={false} - showSuccessMessage={true} - successMessage={ - Object { - "defaultMessage": "Channels index rebuild job triggered successfully.", - "id": "admin.elasticsearch.rebuildIndexSuccessfully.success", - } - } - /> - - } - disabled={false} - errorMessage={ - Object { - "defaultMessage": "Failed to purge indexes: {error}", - "id": "admin.elasticsearch.purgeIndexesButton.error", - } - } - helpText={ - - } - id="purgeIndexesSection" - includeDetailedError={false} - label={ - - } - requestAction={[MockFunction]} - saveNeeded={false} - showSuccessMessage={true} - successMessage={ - Object { - "defaultMessage": "Indexes purged successfully.", - "id": "admin.elasticsearch.purgeIndexesButton.success", - } - } - /> - - } - id="ignoredPurgeIndexes" - label={ - - } - onChange={[Function]} - placeholder={ - Object { - "defaultMessage": "E.g.: .opendistro*,.security*", - "id": "admin.elasticsearch.ignoredPurgeIndexesDescription.example", - } - } - setByEnv={false} - /> - - } - id="enableSearching" - label={ - - } - onChange={[Function]} - setByEnv={false} - value={false} - /> - - } - id="enableAutocomplete" - label={ - - } - onChange={[Function]} - setByEnv={false} - value={false} - /> - - } - id="enableSearchPublicChannelsWithoutMembership" - label={ - - } - onChange={[Function]} - setByEnv={false} - /> -
- - } - /> - + Elasticsearch +
+
- +
+ + Enable Elasticsearch Indexing: + +
+ + +
+ When true, indexing of new posts occurs automatically. Search queries will use database search until "Enable Elasticsearch for search queries" is enabled. + + Learn more about Elasticsearch in our documentation. + +
+
+
+
+ +
+ +
+ The type of the search backend. Changing this setting requires a server restart before taking effect. +
+
+
+
+ +
+ +
+ The address of the Elasticsearch server. + + Please see documentation with server setup instructions. + +
+
+
+
+ +
+ +
+ (Optional) Custom Certificate Authority certificates for the Elasticsearch server. Leave this empty to use the default CAs from the operating system. +
+
+
+
+ +
+ +
+ (Optional) The client certificate for the connection to the Elasticsearch server in the PEM format. +
+
+
+
+ +
+ +
+ (Optional) The key for the client certificate in the PEM format. +
+
+
+
+ + Skip TLS Verification: + +
+ + +
+ When true, Mattermost will not require the Elasticsearch certificate to be signed by a trusted Certificate Authority. +
+
+
+
+ +
+ +
+ (Optional) The username to authenticate to the Elasticsearch server. +
+
+
+
+ +
+ +
+ (Optional) The password to authenticate to the Elasticsearch server. +
+
+
+
+ + Enable Cluster Sniffing: + +
+ + +
+ When true, sniffing finds and connects to all data nodes in your cluster automatically. +
+
+
+
+
+
+ +
+
+ Tests if the Mattermost server can connect to the Elasticsearch server specified. Testing the connection only saves the configuration if the test is successful. A successful test will also re-initialize the client if you have started Elasticsearch after starting Mattermost. But this will not restart the workers. To do that, please toggle "Enable Elasticsearch Indexing". +
+
+
+
+ + Bulk Indexing: + +
+
+
+
+
+ +
+
+ All users, channels and posts in the database will be indexed from oldest to newest. Elasticsearch is available during indexing but search results may be incomplete until the indexing job is complete. +
+
+
+ + + + + + + + + + +
+ Status + + Finish Time + + Run Time + + Details + +
+
+
+
+
+
+
+ +
+
+ +
+
+ This purges the channels index and re-indexes all channels in the database, from oldest to newest. Channel autocomplete is available during indexing but search results may be incomplete until the indexing job is complete. + + + + Note- Please ensure no other indexing job is in progress in the table above. + +
+
+
+
+ +
+
+ +
+
+ Purging will entirely remove the indexes on the Elasticsearch server. Search results may be incomplete until a bulk index of the existing database is rebuilt. +
+
+
+
+ +
+ +
+ When filled in, these indexes will be ignored during the purge, separated by commas. +
+
+
+
+ + Enable Elasticsearch for search queries: + +
+ + +
+ Requires a successful connection to the Elasticsearch server. When true, Elasticsearch will be used for all search queries using the latest index. Search results may be incomplete until a bulk index of the existing post database is finished. When false, database search is used. +
+
+
+
+ + Enable Elasticsearch for autocomplete queries: + +
+ + +
+ Requires a successful connection to the Elasticsearch server. When true, Elasticsearch will be used for all autocompletion queries on users and channels using the latest index. Autocompletion results may be incomplete until a bulk index of the existing users and channels database is finished. When false, database autocomplete is used. +
+
+
+
+ + Allow searching public channels without membership: + +
+ + +
+ When enabled, users can find messages in public channels they have not joined. When enabled for the first time, existing posts will be updated in the background. This process is throttled to avoid impacting search performance. This setting has no effect when Compliance Mode is enabled. +
+
+
- +
+
+ +
+
-
-
+ + `; diff --git a/webapp/channels/src/components/admin_console/brand_image_setting/brand_image_setting.test.tsx b/webapp/channels/src/components/admin_console/brand_image_setting/brand_image_setting.test.tsx index 14145e821f0..6f65ef09781 100644 --- a/webapp/channels/src/components/admin_console/brand_image_setting/brand_image_setting.test.tsx +++ b/webapp/channels/src/components/admin_console/brand_image_setting/brand_image_setting.test.tsx @@ -1,24 +1,30 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {shallow} from 'enzyme'; import React from 'react'; -import {Client4} from 'mattermost-redux/client'; - import {uploadBrandImage, deleteBrandImage} from 'actions/admin_actions.jsx'; +import {renderWithContext, screen, userEvent, waitFor} from 'tests/react_testing_utils'; + import BrandImageSetting from './brand_image_setting'; +// Real implementations are async (await dispatch(...)); mocks must return Promises so handleSave can await them. jest.mock('actions/admin_actions.jsx', () => ({ ...jest.requireActual('actions/admin_actions.jsx'), - uploadBrandImage: jest.fn(), - deleteBrandImage: jest.fn(), + uploadBrandImage: jest.fn(async () => {}), + deleteBrandImage: jest.fn(async () => {}), })); -Client4.setUrl('http://localhost:8065'); - describe('components/admin_console/brand_image_setting', () => { + beforeEach(() => { + jest.spyOn(global, 'fetch').mockResolvedValue({status: 404} as Response); + }); + + afterEach(() => { + jest.restoreAllMocks(); + }); + const baseProps = { disabled: false, setSaveNeeded: jest.fn(), @@ -26,21 +32,71 @@ describe('components/admin_console/brand_image_setting', () => { unRegisterSaveAction: jest.fn(), }; - test('should have called deleteBrandImage or uploadBrandImage on save depending on component state', () => { - const wrapper = shallow( - , + test('should have called deleteBrandImage or uploadBrandImage on save depending on component state', async () => { + let saveAction: (() => Promise) | undefined; + const registerSaveAction = jest.fn((fn: () => Promise) => { + saveAction = fn; + }); + + const {container, unmount} = renderWithContext( + , ); - const instance = wrapper.instance(); + // Wait for componentDidMount fetch to resolve + await waitFor(() => { + expect(registerSaveAction).toHaveBeenCalled(); + }); + expect(saveAction).toBeDefined(); - wrapper.setState({deleteBrandImage: false, brandImage: new Blob(['brand_image_file'])}); - instance.handleSave(); + // Simulate selecting a file via the file input to set brandImage + const file = new File(['brand_image_file'], 'brand.png', {type: 'image/png'}); + const fileInput = container.querySelector('input[type="file"]'); + expect(fileInput).toBeInTheDocument(); + await userEvent.upload(fileInput as HTMLInputElement, file); + + // Now call save - should call uploadBrandImage + await saveAction!(); expect(deleteBrandImage).toHaveBeenCalledTimes(0); expect(uploadBrandImage).toHaveBeenCalledTimes(1); - wrapper.setState({deleteBrandImage: true, brandImage: undefined}); - instance.handleSave(); + // To test deleteBrandImage path, unmount then re-mount with fetch returning 200 + unmount(); + jest.clearAllMocks(); + (global.fetch as jest.Mock).mockResolvedValueOnce({status: 200} as Response); + + let saveAction2: (() => Promise) | undefined; + const registerSaveAction2 = jest.fn((fn: () => Promise) => { + saveAction2 = fn; + }); + + renderWithContext( + , + ); + + await waitFor(() => { + expect(registerSaveAction2).toHaveBeenCalled(); + }); + expect(saveAction2).toBeDefined(); + + // Wait for the brand image to be detected and delete button to appear + await waitFor(() => { + expect(screen.getByText('Ɨ')).toBeInTheDocument(); + }); + const deleteButton = screen.getByText('Ɨ').closest('button')!; + await userEvent.click(deleteButton); + + await waitFor(() => { + expect(screen.getByText('No brand image uploaded')).toBeInTheDocument(); + }); + + await saveAction2!(); expect(deleteBrandImage).toHaveBeenCalledTimes(1); - expect(uploadBrandImage).toHaveBeenCalledTimes(1); + expect(uploadBrandImage).toHaveBeenCalledTimes(0); }); }); diff --git a/webapp/channels/src/components/admin_console/database/__snapshots__/migrations_table.test.tsx.snap b/webapp/channels/src/components/admin_console/database/__snapshots__/migrations_table.test.tsx.snap index 899579e1a01..66f4be792b0 100644 --- a/webapp/channels/src/components/admin_console/database/__snapshots__/migrations_table.test.tsx.snap +++ b/webapp/channels/src/components/admin_console/database/__snapshots__/migrations_table.test.tsx.snap @@ -1,42 +1,35 @@ // Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing exports[`components/MigrationsTable should match snapshot when there are no migrations 1`] = ` -
+
- -
-
- - - - - - - - -
- - - -
+ All applied migrations. +
+
+ + + + + + + + +
+ Version + + Name +
+
`; diff --git a/webapp/channels/src/components/admin_console/database/migrations_table.test.tsx b/webapp/channels/src/components/admin_console/database/migrations_table.test.tsx index dafd28c90e5..e9f16bccf72 100644 --- a/webapp/channels/src/components/admin_console/database/migrations_table.test.tsx +++ b/webapp/channels/src/components/admin_console/database/migrations_table.test.tsx @@ -2,7 +2,6 @@ // See LICENSE.txt for license information. import {act, screen, waitFor} from '@testing-library/react'; -import {shallow} from 'enzyme'; import React from 'react'; import {FormattedMessage} from 'react-intl'; @@ -34,13 +33,18 @@ describe('components/MigrationsTable', () => { }, }; - test('should match snapshot when there are no migrations', () => { - const wrapper = shallow( + test('should match snapshot when there are no migrations', async () => { + const {container} = renderWithContext( ); + />, + ); - expect(wrapper).toMatchSnapshot(); + await waitFor(() => { + expect(baseProps.actions.getAppliedSchemaMigrations).toHaveBeenCalledTimes(1); + }); + + expect(container).toMatchSnapshot(); }); test('should have called actions.getAppliedSchemaMigrations only when first rendered', async () => { diff --git a/webapp/channels/src/components/admin_console/database_settings.test.tsx b/webapp/channels/src/components/admin_console/database_settings.test.tsx index 317c0a74020..29f2542e17b 100644 --- a/webapp/channels/src/components/admin_console/database_settings.test.tsx +++ b/webapp/channels/src/components/admin_console/database_settings.test.tsx @@ -1,11 +1,12 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {shallow} from 'enzyme'; import React from 'react'; import DatabaseSettings from 'components/admin_console/database_settings'; +import {renderWithContext} from 'tests/react_testing_utils'; + jest.mock('actions/admin_actions.jsx', () => { const pingFn = () => { return jest.fn(() => { @@ -47,11 +48,11 @@ describe('components/DatabaseSettings', () => { config, isDisabled: false, }; - const wrapper = shallow( + const {container} = renderWithContext( , ); - expect(wrapper).toMatchSnapshot(); + expect(container).toMatchSnapshot(); }); }); diff --git a/webapp/channels/src/components/admin_console/elasticsearch_settings.test.tsx b/webapp/channels/src/components/admin_console/elasticsearch_settings.test.tsx index f5f034715a7..43bfdc251fe 100644 --- a/webapp/channels/src/components/admin_console/elasticsearch_settings.test.tsx +++ b/webapp/channels/src/components/admin_console/elasticsearch_settings.test.tsx @@ -1,13 +1,13 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {shallow} from 'enzyme'; import React from 'react'; import type {AdminConfig} from '@mattermost/types/config'; import ElasticSearchSettings from 'components/admin_console/elasticsearch_settings'; -import SaveButton from 'components/save_button'; + +import {renderWithContext, screen, userEvent} from 'tests/react_testing_utils'; jest.mock('actions/admin_actions.jsx', () => { return { @@ -22,6 +22,7 @@ describe('components/ElasticSearchSettings', () => { const config = { ElasticsearchSettings: { ConnectionURL: 'test', + Backend: '', SkipTLSVerification: false, CA: 'test.ca', ClientCert: 'test.crt', @@ -32,20 +33,24 @@ describe('components/ElasticSearchSettings', () => { EnableIndexing: false, EnableSearching: false, EnableAutocomplete: false, + EnableSearchPublicChannelsWithoutMembership: false, + IgnoredPurgeIndexes: '', }, }; - const wrapper = shallow( + const {container} = renderWithContext( , ); - expect(wrapper).toMatchSnapshot(); + expect(container).toMatchSnapshot(); }); test('should match snapshot, enabled', () => { const config = { ElasticsearchSettings: { ConnectionURL: 'test', + Backend: '', SkipTLSVerification: false, CA: 'test.ca', ClientCert: 'test.crt', @@ -56,43 +61,60 @@ describe('components/ElasticSearchSettings', () => { EnableIndexing: true, EnableSearching: false, EnableAutocomplete: false, + EnableSearchPublicChannelsWithoutMembership: false, + IgnoredPurgeIndexes: '', }, }; - const wrapper = shallow( + const {container} = renderWithContext( , ); - expect(wrapper).toMatchSnapshot(); + expect(container).toMatchSnapshot(); }); - test('should maintain save disable until is tested', () => { + test('should maintain save disable until is tested', async () => { const config = { ElasticsearchSettings: { ConnectionURL: 'test', + Backend: '', SkipTLSVerification: false, + CA: '', + ClientCert: '', + ClientKey: '', Username: 'test', Password: 'test', Sniff: false, EnableIndexing: false, EnableSearching: false, EnableAutocomplete: false, + EnableSearchPublicChannelsWithoutMembership: false, + IgnoredPurgeIndexes: '', }, }; - const wrapper = shallow( + renderWithContext( , ); - const instance = wrapper.instance() as any; - expect(wrapper.find(SaveButton).prop('disabled')).toBe(true); - instance.handleSettingChanged('enableIndexing', true); - expect(wrapper.find(SaveButton).prop('disabled')).toBe(true); - const success = jest.fn(); - const error = jest.fn(); - instance.doTestConfig(success, error); - expect(success).toHaveBeenCalled(); - expect(error).not.toHaveBeenCalled(); - expect(wrapper.find(SaveButton).prop('disabled')).toBe(false); + + // Save button should be disabled initially (no changes) + expect(screen.getByTestId('saveSetting')).toBeDisabled(); + + // Enable indexing by clicking the true radio for enableIndexing + const enableIndexingTrue = screen.getByTestId('enableIndexingtrue'); + await userEvent.click(enableIndexingTrue); + + // Save button should still be disabled because config hasn't been tested + expect(screen.getByTestId('saveSetting')).toBeDisabled(); + + // Click Test Connection button to test config + const testButton = screen.getByText('Test Connection'); + await userEvent.click(testButton); + + // After successful test, save button should be enabled + expect(screen.getByTestId('saveSetting')).not.toBeDisabled(); }); }); diff --git a/webapp/channels/src/components/admin_console/manage_teams_modal/__snapshots__/manage_teams_dropdown.test.tsx.snap b/webapp/channels/src/components/admin_console/manage_teams_modal/__snapshots__/manage_teams_dropdown.test.tsx.snap index d340852f477..09dfa4b53d4 100644 --- a/webapp/channels/src/components/admin_console/manage_teams_modal/__snapshots__/manage_teams_dropdown.test.tsx.snap +++ b/webapp/channels/src/components/admin_console/manage_teams_modal/__snapshots__/manage_teams_dropdown.test.tsx.snap @@ -1,149 +1,73 @@ // Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing exports[`ManageTeamsDropdown should match snapshot for guest 1`] = ` - - - - Guest - - - - - + - + + + Guest + + + + + + `; exports[`ManageTeamsDropdown should match snapshot for system admin 1`] = ` - - - - System Admin - - - - - + - + + + System Admin + + + + + + `; exports[`ManageTeamsDropdown should match snapshot for team admin 1`] = ` - - - - Team Admin - - - - - + - + + + Team Admin + + + + + + `; exports[`ManageTeamsDropdown should match snapshot for team member 1`] = ` - - - - Team Member - - - - - + - + + + Team Member + + + + + + `; diff --git a/webapp/channels/src/components/admin_console/manage_teams_modal/__snapshots__/manage_teams_modal.test.tsx.snap b/webapp/channels/src/components/admin_console/manage_teams_modal/__snapshots__/manage_teams_modal.test.tsx.snap index 99a0a80e303..d9c64d12759 100644 --- a/webapp/channels/src/components/admin_console/manage_teams_modal/__snapshots__/manage_teams_modal.test.tsx.snap +++ b/webapp/channels/src/components/admin_console/manage_teams_modal/__snapshots__/manage_teams_modal.test.tsx.snap @@ -1,85 +1,95 @@ // Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing exports[`ManageTeamsModal should match snapshot init 1`] = ` - -