OIDC: unit test ServerPickerDialog (#11019)
* add aria-label to default homeserver checkbox * test ServerPickerDialog * remove debug * strict fixes * use testid instead of aria-label * i18n
This commit is contained in:
parent
e9a8f4a11d
commit
a28f44a075
3 changed files with 384 additions and 0 deletions
|
@ -202,6 +202,7 @@ export default class ServerPickerDialog extends React.PureComponent<IProps, ISta
|
|||
value="true"
|
||||
checked={this.state.defaultChosen}
|
||||
onChange={this.onDefaultChosen}
|
||||
data-testid="defaultHomeserver"
|
||||
>
|
||||
{defaultServerName}
|
||||
</StyledRadioButton>
|
||||
|
|
241
test/components/views/dialogs/ServerPickerDialog-test.tsx
Normal file
241
test/components/views/dialogs/ServerPickerDialog-test.tsx
Normal file
|
@ -0,0 +1,241 @@
|
|||
/*
|
||||
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";
|
||||
|
||||
// Fake random strings to give a predictable snapshot for IDs
|
||||
jest.mock("matrix-js-sdk/src/randomstring", () => ({
|
||||
randomString: () => "abdefghi",
|
||||
}));
|
||||
|
||||
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();
|
||||
});
|
||||
|
||||
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"));
|
||||
|
||||
// serverpicker still validates the 'other homeserver' field on submit
|
||||
// when default is chosen
|
||||
// so this throws a lot of errors into the console
|
||||
// and is asynchronous while waiting for validation
|
||||
await flushPromises();
|
||||
|
||||
// closed dialog with default server
|
||||
expect(onFinished).toHaveBeenCalledWith(defaultServerConfig);
|
||||
});
|
||||
|
||||
it("should submit successfully with a valid custom homeserver", async () => {
|
||||
const homeserver = "https://myhomeserver.site";
|
||||
fetchMock.get(`${homeserver}/_matrix/client/versions`, {
|
||||
unstable_features: {},
|
||||
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: [],
|
||||
});
|
||||
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: ["1"] });
|
||||
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,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,142 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`<ServerPickerDialog /> should render dialog 1`] = `
|
||||
<div>
|
||||
<div
|
||||
data-focus-guard="true"
|
||||
style="width: 1px; height: 0px; padding: 0px; overflow: hidden; position: fixed; top: 1px; left: 1px;"
|
||||
tabindex="0"
|
||||
/>
|
||||
<div
|
||||
aria-describedby="mx_ServerPickerDialog"
|
||||
aria-labelledby="mx_BaseDialog_title"
|
||||
class="mx_ServerPickerDialog"
|
||||
data-focus-lock-disabled="false"
|
||||
role="dialog"
|
||||
>
|
||||
<div
|
||||
class="mx_Dialog_header mx_Dialog_headerWithCancel"
|
||||
>
|
||||
<h2
|
||||
class="mx_Heading_h2 mx_Dialog_title"
|
||||
id="mx_BaseDialog_title"
|
||||
>
|
||||
Sign into your homeserver
|
||||
</h2>
|
||||
<div
|
||||
aria-label="Close dialog"
|
||||
class="mx_AccessibleButton mx_Dialog_cancelButton"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
/>
|
||||
</div>
|
||||
<form
|
||||
class="mx_Dialog_content"
|
||||
id="mx_ServerPickerDialog"
|
||||
>
|
||||
<p>
|
||||
We call the places where you can host your account 'homeservers'.
|
||||
|
||||
Matrix.org is the biggest public homeserver in the world, so it's a good place for many.
|
||||
</p>
|
||||
<label
|
||||
class="mx_StyledRadioButton mx_StyledRadioButton_enabled"
|
||||
>
|
||||
<input
|
||||
checked=""
|
||||
data-testid="defaultHomeserver"
|
||||
name="defaultChosen"
|
||||
type="radio"
|
||||
value="true"
|
||||
/>
|
||||
<div>
|
||||
<div />
|
||||
</div>
|
||||
<div
|
||||
class="mx_StyledRadioButton_content"
|
||||
>
|
||||
<div
|
||||
aria-describedby="mx_TooltipTarget_abdefghi"
|
||||
class="mx_TextWithTooltip_target mx_Login_underlinedServerName"
|
||||
tabindex="0"
|
||||
>
|
||||
matrix.org
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="mx_StyledRadioButton_spacer"
|
||||
/>
|
||||
</label>
|
||||
<div
|
||||
class="mx_StyledRadioButton mx_ServerPickerDialog_otherHomeserverRadio mx_StyledRadioButton_enabled mx_StyledRadioButton_checked"
|
||||
>
|
||||
<label
|
||||
class="mx_StyledRadioButton_innerLabel"
|
||||
>
|
||||
<input
|
||||
aria-label="Other homeserver"
|
||||
name="defaultChosen"
|
||||
type="radio"
|
||||
value="false"
|
||||
/>
|
||||
<div>
|
||||
<div />
|
||||
</div>
|
||||
</label>
|
||||
<div
|
||||
class="mx_StyledRadioButton_content"
|
||||
>
|
||||
<div
|
||||
class="mx_Field mx_Field_input mx_ServerPickerDialog_otherHomeserver"
|
||||
>
|
||||
<input
|
||||
id="mx_homeserverInput"
|
||||
label="Other homeserver"
|
||||
placeholder="Other homeserver"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
<label
|
||||
for="mx_homeserverInput"
|
||||
>
|
||||
Other homeserver
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="mx_StyledRadioButton_spacer"
|
||||
/>
|
||||
</div>
|
||||
<p>
|
||||
Use your preferred Matrix homeserver if you have one, or host your own.
|
||||
</p>
|
||||
<div
|
||||
class="mx_AccessibleButton mx_ServerPickerDialog_continue mx_AccessibleButton_hasKind mx_AccessibleButton_kind_primary"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
Continue
|
||||
</div>
|
||||
<h2>
|
||||
Learn more
|
||||
</h2>
|
||||
<a
|
||||
class="mx_ExternalLink"
|
||||
href="https://matrix.org/faq/#what-is-a-homeserver%3F"
|
||||
rel="noreferrer noopener"
|
||||
target="_blank"
|
||||
>
|
||||
About homeservers
|
||||
<i
|
||||
class="mx_ExternalLink_icon"
|
||||
/>
|
||||
</a>
|
||||
</form>
|
||||
</div>
|
||||
<div
|
||||
data-focus-guard="true"
|
||||
style="width: 1px; height: 0px; padding: 0px; overflow: hidden; position: fixed; top: 1px; left: 1px;"
|
||||
tabindex="0"
|
||||
/>
|
||||
</div>
|
||||
`;
|
Loading…
Reference in a new issue