270 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			TypeScript
		
	
	
			
		
		
	
	
			270 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			TypeScript
		
	
	
| /*
 | |
| Copyright 2023 The Matrix.org Foundation C.I.C.
 | |
| 
 | |
| Licensed under the Apache License, Version 2.0 (the "License");
 | |
| you may not use this file except in compliance with the License.
 | |
| You may obtain a copy of the License at
 | |
| 
 | |
|     http://www.apache.org/licenses/LICENSE-2.0
 | |
| 
 | |
| Unless required by applicable law or agreed to in writing, software
 | |
| distributed under the License is distributed on an "AS IS" BASIS,
 | |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | |
| See the License for the specific language governing permissions and
 | |
| limitations under the License.
 | |
| */
 | |
| 
 | |
| import React from "react";
 | |
| import { fireEvent, render, screen } from "@testing-library/react";
 | |
| import fetchMock from "fetch-mock-jest";
 | |
| 
 | |
| import ServerPickerDialog from "../../../../src/components/views/dialogs/ServerPickerDialog";
 | |
| import SdkConfig from "../../../../src/SdkConfig";
 | |
| import { flushPromises } from "../../../test-utils";
 | |
| import { ValidatedServerConfig } from "../../../../src/utils/ValidatedServerConfig";
 | |
| 
 | |
| /** The matrix versions our mock server claims to support */
 | |
| const SERVER_SUPPORTED_MATRIX_VERSIONS = ["v1.1", "v1.5", "v1.6", "v1.8", "v1.9"];
 | |
| 
 | |
| describe("<ServerPickerDialog />", () => {
 | |
|     const defaultServerConfig = {
 | |
|         hsUrl: "https://matrix.org",
 | |
|         hsName: "matrix.org",
 | |
|         hsNameIsDifferent: true,
 | |
|         isUrl: "https://is.org",
 | |
|         isDefault: true,
 | |
|         isNameResolvable: true,
 | |
|         warning: "",
 | |
|     };
 | |
|     const wkHsUrl = "https://hsbaseurlfrom.wk";
 | |
|     const wkIsUrl = "https://isbaseurlfrom.wk";
 | |
|     const validWellKnown = {
 | |
|         "m.homeserver": {
 | |
|             base_url: wkHsUrl,
 | |
|         },
 | |
|         "m.identity_server": {
 | |
|             base_url: wkIsUrl,
 | |
|         },
 | |
|     };
 | |
|     const defaultProps = {
 | |
|         serverConfig: defaultServerConfig,
 | |
|         onFinished: jest.fn(),
 | |
|     };
 | |
|     const getComponent = (
 | |
|         props: Partial<{
 | |
|             onFinished: any;
 | |
|             serverConfig: ValidatedServerConfig;
 | |
|         }> = {},
 | |
|     ) => render(<ServerPickerDialog {...defaultProps} {...props} />);
 | |
| 
 | |
|     beforeEach(() => {
 | |
|         SdkConfig.add({
 | |
|             validated_server_config: defaultServerConfig,
 | |
|         });
 | |
| 
 | |
|         fetchMock.resetHistory();
 | |
|         fetchMock.catch({
 | |
|             status: 404,
 | |
|             body: '{"errcode": "M_UNRECOGNIZED", "error": "Unrecognized request"}',
 | |
|             headers: { "content-type": "application/json" },
 | |
|         });
 | |
|     });
 | |
| 
 | |
|     it("should render dialog", () => {
 | |
|         const { container } = getComponent();
 | |
|         expect(container).toMatchSnapshot();
 | |
|     });
 | |
| 
 | |
|     // checkbox and text input have the same aria-label
 | |
|     const getOtherHomeserverCheckBox = () =>
 | |
|         screen.getAllByLabelText("Other homeserver").find((node) => node.getAttribute("type") === "radio")!;
 | |
|     const getOtherHomeserverInput = () =>
 | |
|         screen.getAllByLabelText("Other homeserver").find((node) => node.getAttribute("type") === "text")!;
 | |
| 
 | |
|     describe("when default server config is selected", () => {
 | |
|         it("should select other homeserver field on open", () => {
 | |
|             getComponent();
 | |
|             expect(getOtherHomeserverCheckBox()).toBeChecked();
 | |
|             // empty field
 | |
|             expect(getOtherHomeserverInput()).toHaveDisplayValue("");
 | |
|         });
 | |
| 
 | |
|         it("should display an error when trying to continue with an empty homeserver field", async () => {
 | |
|             const onFinished = jest.fn();
 | |
|             const { container } = getComponent({ onFinished });
 | |
| 
 | |
|             fireEvent.click(screen.getByText("Continue"));
 | |
| 
 | |
|             await flushPromises();
 | |
| 
 | |
|             // error on field
 | |
|             expect(container.querySelector(".mx_ServerPickerDialog_otherHomeserver.mx_Field_invalid")).toBeTruthy();
 | |
| 
 | |
|             // didn't close dialog
 | |
|             expect(onFinished).not.toHaveBeenCalled();
 | |
|         });
 | |
| 
 | |
|         it("should close when selecting default homeserver and clicking continue", async () => {
 | |
|             const onFinished = jest.fn();
 | |
|             getComponent({ onFinished });
 | |
| 
 | |
|             fireEvent.click(screen.getByTestId("defaultHomeserver"));
 | |
|             expect(screen.getByTestId("defaultHomeserver")).toBeChecked();
 | |
| 
 | |
|             fireEvent.click(screen.getByText("Continue"));
 | |
| 
 | |
|             // closed dialog with default server
 | |
|             expect(onFinished).toHaveBeenCalledWith(defaultServerConfig);
 | |
|         });
 | |
| 
 | |
|         it("should allow user to revert from a custom server to the default", async () => {
 | |
|             fetchMock.get(`https://custom.org/_matrix/client/versions`, {
 | |
|                 unstable_features: {},
 | |
|                 versions: SERVER_SUPPORTED_MATRIX_VERSIONS,
 | |
|             });
 | |
| 
 | |
|             const onFinished = jest.fn();
 | |
|             const serverConfig = {
 | |
|                 hsUrl: "https://custom.org",
 | |
|                 hsName: "custom.org",
 | |
|                 hsNameIsDifferent: true,
 | |
|                 isUrl: "https://is.org",
 | |
|                 isDefault: false,
 | |
|                 isNameResolvable: true,
 | |
|                 warning: "",
 | |
|             };
 | |
|             getComponent({ onFinished, serverConfig });
 | |
| 
 | |
|             fireEvent.click(screen.getByTestId("defaultHomeserver"));
 | |
|             expect(screen.getByTestId("defaultHomeserver")).toBeChecked();
 | |
| 
 | |
|             fireEvent.click(screen.getByText("Continue"));
 | |
|             await flushPromises();
 | |
| 
 | |
|             // closed dialog with default server and nothing else
 | |
|             expect(onFinished).toHaveBeenCalledWith(defaultServerConfig);
 | |
|             expect(onFinished).toHaveBeenCalledTimes(1);
 | |
|         });
 | |
| 
 | |
|         it("should submit successfully with a valid custom homeserver", async () => {
 | |
|             const homeserver = "https://myhomeserver.site";
 | |
|             fetchMock.get(`${homeserver}/_matrix/client/versions`, {
 | |
|                 unstable_features: {},
 | |
|                 versions: SERVER_SUPPORTED_MATRIX_VERSIONS,
 | |
|             });
 | |
|             const onFinished = jest.fn();
 | |
|             getComponent({ onFinished });
 | |
| 
 | |
|             fireEvent.change(getOtherHomeserverInput(), { target: { value: homeserver } });
 | |
|             expect(getOtherHomeserverInput()).toHaveDisplayValue(homeserver);
 | |
| 
 | |
|             fireEvent.click(screen.getByText("Continue"));
 | |
| 
 | |
|             // validation on submit is async
 | |
|             await flushPromises();
 | |
| 
 | |
|             // closed dialog with validated custom server
 | |
|             expect(onFinished).toHaveBeenCalledWith({
 | |
|                 hsName: "myhomeserver.site",
 | |
|                 hsUrl: homeserver,
 | |
|                 hsNameIsDifferent: false,
 | |
|                 warning: null,
 | |
|                 isDefault: false,
 | |
|                 isNameResolvable: false,
 | |
|                 isUrl: defaultServerConfig.isUrl,
 | |
|             });
 | |
|         });
 | |
| 
 | |
|         describe("validates custom homeserver", () => {
 | |
|             it("should lookup .well-known for homeserver without protocol", async () => {
 | |
|                 const homeserver = "myhomeserver1.site";
 | |
|                 const wellKnownUrl = `https://${homeserver}/.well-known/matrix/client`;
 | |
|                 fetchMock.get(wellKnownUrl, {});
 | |
|                 getComponent();
 | |
| 
 | |
|                 fireEvent.change(getOtherHomeserverInput(), { target: { value: homeserver } });
 | |
|                 expect(getOtherHomeserverInput()).toHaveDisplayValue(homeserver);
 | |
|                 // trigger validation
 | |
|                 fireEvent.blur(getOtherHomeserverInput());
 | |
| 
 | |
|                 // validation on submit is async
 | |
|                 await flushPromises();
 | |
| 
 | |
|                 expect(fetchMock).toHaveFetched(wellKnownUrl);
 | |
|             });
 | |
| 
 | |
|             it("should submit using validated config from a valid .well-known", async () => {
 | |
|                 const homeserver = "myhomeserver2.site";
 | |
|                 const wellKnownUrl = `https://${homeserver}/.well-known/matrix/client`;
 | |
| 
 | |
|                 // urls from homeserver well-known
 | |
|                 const versionsUrl = `${wkHsUrl}/_matrix/client/versions`;
 | |
|                 const isWellKnownUrl = `${wkIsUrl}/_matrix/identity/v2`;
 | |
| 
 | |
|                 fetchMock.getOnce(wellKnownUrl, validWellKnown);
 | |
|                 fetchMock.getOnce(versionsUrl, {
 | |
|                     versions: SERVER_SUPPORTED_MATRIX_VERSIONS,
 | |
|                 });
 | |
|                 fetchMock.getOnce(isWellKnownUrl, {});
 | |
|                 const onFinished = jest.fn();
 | |
|                 getComponent({ onFinished });
 | |
| 
 | |
|                 fireEvent.change(getOtherHomeserverInput(), { target: { value: homeserver } });
 | |
|                 fireEvent.click(screen.getByText("Continue"));
 | |
| 
 | |
|                 // validation on submit is async
 | |
|                 await flushPromises();
 | |
| 
 | |
|                 expect(fetchMock).toHaveFetched(wellKnownUrl);
 | |
|                 // fetched using urls from .well-known
 | |
|                 expect(fetchMock).toHaveFetched(versionsUrl);
 | |
|                 expect(fetchMock).toHaveFetched(isWellKnownUrl);
 | |
| 
 | |
|                 expect(onFinished).toHaveBeenCalledWith({
 | |
|                     hsName: homeserver,
 | |
|                     hsUrl: wkHsUrl,
 | |
|                     hsNameIsDifferent: true,
 | |
|                     warning: null,
 | |
|                     isDefault: false,
 | |
|                     isNameResolvable: true,
 | |
|                     isUrl: wkIsUrl,
 | |
|                 });
 | |
| 
 | |
|                 await flushPromises();
 | |
|             });
 | |
| 
 | |
|             it("should fall back to static config when well-known lookup fails", async () => {
 | |
|                 const homeserver = "myhomeserver3.site";
 | |
|                 // this server returns 404 for well-known
 | |
|                 const wellKnownUrl = `https://${homeserver}/.well-known/matrix/client`;
 | |
|                 fetchMock.get(wellKnownUrl, { status: 404 });
 | |
|                 // but is otherwise live (happy versions response)
 | |
|                 fetchMock.get(`https://${homeserver}/_matrix/client/versions`, {
 | |
|                     versions: SERVER_SUPPORTED_MATRIX_VERSIONS,
 | |
|                 });
 | |
|                 const onFinished = jest.fn();
 | |
|                 getComponent({ onFinished });
 | |
| 
 | |
|                 fireEvent.change(getOtherHomeserverInput(), { target: { value: homeserver } });
 | |
|                 fireEvent.click(screen.getByText("Continue"));
 | |
| 
 | |
|                 // validation on submit is async
 | |
|                 await flushPromises();
 | |
| 
 | |
|                 expect(fetchMock).toHaveFetched(wellKnownUrl);
 | |
|                 expect(fetchMock).toHaveFetched(`https://${homeserver}/_matrix/client/versions`);
 | |
| 
 | |
|                 expect(onFinished).toHaveBeenCalledWith({
 | |
|                     hsName: homeserver,
 | |
|                     hsUrl: "https://" + homeserver,
 | |
|                     hsNameIsDifferent: false,
 | |
|                     warning: null,
 | |
|                     isDefault: false,
 | |
|                     isNameResolvable: false,
 | |
|                     isUrl: defaultServerConfig.isUrl,
 | |
|                 });
 | |
|             });
 | |
|         });
 | |
|     });
 | |
| });
 |