Skip to content
This repository was archived by the owner on Sep 11, 2024. It is now read-only.

Commit a28f44a

Browse files
author
Kerry
authored
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
1 parent e9a8f4a commit a28f44a

File tree

3 files changed

+384
-0
lines changed

3 files changed

+384
-0
lines changed

src/components/views/dialogs/ServerPickerDialog.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,7 @@ export default class ServerPickerDialog extends React.PureComponent<IProps, ISta
202202
value="true"
203203
checked={this.state.defaultChosen}
204204
onChange={this.onDefaultChosen}
205+
data-testid="defaultHomeserver"
205206
>
206207
{defaultServerName}
207208
</StyledRadioButton>
Lines changed: 241 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,241 @@
1+
/*
2+
Copyright 2023 The Matrix.org Foundation C.I.C.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
import React from "react";
18+
import { fireEvent, render, screen } from "@testing-library/react";
19+
import fetchMock from "fetch-mock-jest";
20+
21+
import ServerPickerDialog from "../../../../src/components/views/dialogs/ServerPickerDialog";
22+
import SdkConfig from "../../../../src/SdkConfig";
23+
import { flushPromises } from "../../../test-utils";
24+
import { ValidatedServerConfig } from "../../../../src/utils/ValidatedServerConfig";
25+
26+
// Fake random strings to give a predictable snapshot for IDs
27+
jest.mock("matrix-js-sdk/src/randomstring", () => ({
28+
randomString: () => "abdefghi",
29+
}));
30+
31+
describe("<ServerPickerDialog />", () => {
32+
const defaultServerConfig = {
33+
hsUrl: "https://matrix.org",
34+
hsName: "matrix.org",
35+
hsNameIsDifferent: true,
36+
isUrl: "https://is.org",
37+
isDefault: true,
38+
isNameResolvable: true,
39+
warning: "",
40+
};
41+
const wkHsUrl = "https://hsbaseurlfrom.wk";
42+
const wkIsUrl = "https://isbaseurlfrom.wk";
43+
const validWellKnown = {
44+
"m.homeserver": {
45+
base_url: wkHsUrl,
46+
},
47+
"m.identity_server": {
48+
base_url: wkIsUrl,
49+
},
50+
};
51+
const defaultProps = {
52+
serverConfig: defaultServerConfig,
53+
onFinished: jest.fn(),
54+
};
55+
const getComponent = (
56+
props: Partial<{
57+
onFinished: any;
58+
serverConfig: ValidatedServerConfig;
59+
}> = {},
60+
) => render(<ServerPickerDialog {...defaultProps} {...props} />);
61+
62+
beforeEach(() => {
63+
SdkConfig.add({
64+
validated_server_config: defaultServerConfig,
65+
});
66+
67+
fetchMock.resetHistory();
68+
});
69+
70+
it("should render dialog", () => {
71+
const { container } = getComponent();
72+
expect(container).toMatchSnapshot();
73+
});
74+
75+
// checkbox and text input have the same aria-label
76+
const getOtherHomeserverCheckBox = () =>
77+
screen.getAllByLabelText("Other homeserver").find((node) => node.getAttribute("type") === "radio")!;
78+
const getOtherHomeserverInput = () =>
79+
screen.getAllByLabelText("Other homeserver").find((node) => node.getAttribute("type") === "text")!;
80+
81+
describe("when default server config is selected", () => {
82+
it("should select other homeserver field on open", () => {
83+
getComponent();
84+
expect(getOtherHomeserverCheckBox()).toBeChecked();
85+
// empty field
86+
expect(getOtherHomeserverInput()).toHaveDisplayValue("");
87+
});
88+
89+
it("should display an error when trying to continue with an empty homeserver field", async () => {
90+
const onFinished = jest.fn();
91+
const { container } = getComponent({ onFinished });
92+
93+
fireEvent.click(screen.getByText("Continue"));
94+
95+
await flushPromises();
96+
97+
// error on field
98+
expect(container.querySelector(".mx_ServerPickerDialog_otherHomeserver.mx_Field_invalid")).toBeTruthy();
99+
100+
// didn't close dialog
101+
expect(onFinished).not.toHaveBeenCalled();
102+
});
103+
104+
it("should close when selecting default homeserver and clicking continue", async () => {
105+
const onFinished = jest.fn();
106+
getComponent({ onFinished });
107+
108+
fireEvent.click(screen.getByTestId("defaultHomeserver"));
109+
expect(screen.getByTestId("defaultHomeserver")).toBeChecked();
110+
111+
fireEvent.click(screen.getByText("Continue"));
112+
113+
// serverpicker still validates the 'other homeserver' field on submit
114+
// when default is chosen
115+
// so this throws a lot of errors into the console
116+
// and is asynchronous while waiting for validation
117+
await flushPromises();
118+
119+
// closed dialog with default server
120+
expect(onFinished).toHaveBeenCalledWith(defaultServerConfig);
121+
});
122+
123+
it("should submit successfully with a valid custom homeserver", async () => {
124+
const homeserver = "https://myhomeserver.site";
125+
fetchMock.get(`${homeserver}/_matrix/client/versions`, {
126+
unstable_features: {},
127+
versions: [],
128+
});
129+
const onFinished = jest.fn();
130+
getComponent({ onFinished });
131+
132+
fireEvent.change(getOtherHomeserverInput(), { target: { value: homeserver } });
133+
expect(getOtherHomeserverInput()).toHaveDisplayValue(homeserver);
134+
135+
fireEvent.click(screen.getByText("Continue"));
136+
137+
// validation on submit is async
138+
await flushPromises();
139+
140+
// closed dialog with validated custom server
141+
expect(onFinished).toHaveBeenCalledWith({
142+
hsName: "myhomeserver.site",
143+
hsUrl: homeserver,
144+
hsNameIsDifferent: false,
145+
warning: null,
146+
isDefault: false,
147+
isNameResolvable: false,
148+
isUrl: defaultServerConfig.isUrl,
149+
});
150+
});
151+
152+
describe("validates custom homeserver", () => {
153+
it("should lookup .well-known for homeserver without protocol", async () => {
154+
const homeserver = "myhomeserver1.site";
155+
const wellKnownUrl = `https://${homeserver}/.well-known/matrix/client`;
156+
fetchMock.get(wellKnownUrl, {});
157+
getComponent();
158+
159+
fireEvent.change(getOtherHomeserverInput(), { target: { value: homeserver } });
160+
expect(getOtherHomeserverInput()).toHaveDisplayValue(homeserver);
161+
// trigger validation
162+
fireEvent.blur(getOtherHomeserverInput());
163+
164+
// validation on submit is async
165+
await flushPromises();
166+
167+
expect(fetchMock).toHaveFetched(wellKnownUrl);
168+
});
169+
170+
it("should submit using validated config from a valid .well-known", async () => {
171+
const homeserver = "myhomeserver2.site";
172+
const wellKnownUrl = `https://${homeserver}/.well-known/matrix/client`;
173+
174+
// urls from homeserver well-known
175+
const versionsUrl = `${wkHsUrl}/_matrix/client/versions`;
176+
const isWellKnownUrl = `${wkIsUrl}/_matrix/identity/v2`;
177+
178+
fetchMock.getOnce(wellKnownUrl, validWellKnown);
179+
fetchMock.getOnce(versionsUrl, {
180+
versions: [],
181+
});
182+
fetchMock.getOnce(isWellKnownUrl, {});
183+
const onFinished = jest.fn();
184+
getComponent({ onFinished });
185+
186+
fireEvent.change(getOtherHomeserverInput(), { target: { value: homeserver } });
187+
fireEvent.click(screen.getByText("Continue"));
188+
189+
// validation on submit is async
190+
await flushPromises();
191+
192+
expect(fetchMock).toHaveFetched(wellKnownUrl);
193+
// fetched using urls from .well-known
194+
expect(fetchMock).toHaveFetched(versionsUrl);
195+
expect(fetchMock).toHaveFetched(isWellKnownUrl);
196+
197+
expect(onFinished).toHaveBeenCalledWith({
198+
hsName: homeserver,
199+
hsUrl: wkHsUrl,
200+
hsNameIsDifferent: true,
201+
warning: null,
202+
isDefault: false,
203+
isNameResolvable: true,
204+
isUrl: wkIsUrl,
205+
});
206+
207+
await flushPromises();
208+
});
209+
210+
it("should fall back to static config when well-known lookup fails", async () => {
211+
const homeserver = "myhomeserver3.site";
212+
// this server returns 404 for well-known
213+
const wellKnownUrl = `https://${homeserver}/.well-known/matrix/client`;
214+
fetchMock.get(wellKnownUrl, { status: 404 });
215+
// but is otherwise live (happy versions response)
216+
fetchMock.get(`https://${homeserver}/_matrix/client/versions`, { versions: ["1"] });
217+
const onFinished = jest.fn();
218+
getComponent({ onFinished });
219+
220+
fireEvent.change(getOtherHomeserverInput(), { target: { value: homeserver } });
221+
fireEvent.click(screen.getByText("Continue"));
222+
223+
// validation on submit is async
224+
await flushPromises();
225+
226+
expect(fetchMock).toHaveFetched(wellKnownUrl);
227+
expect(fetchMock).toHaveFetched(`https://${homeserver}/_matrix/client/versions`);
228+
229+
expect(onFinished).toHaveBeenCalledWith({
230+
hsName: homeserver,
231+
hsUrl: "https://" + homeserver,
232+
hsNameIsDifferent: false,
233+
warning: null,
234+
isDefault: false,
235+
isNameResolvable: false,
236+
isUrl: defaultServerConfig.isUrl,
237+
});
238+
});
239+
});
240+
});
241+
});
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`<ServerPickerDialog /> should render dialog 1`] = `
4+
<div>
5+
<div
6+
data-focus-guard="true"
7+
style="width: 1px; height: 0px; padding: 0px; overflow: hidden; position: fixed; top: 1px; left: 1px;"
8+
tabindex="0"
9+
/>
10+
<div
11+
aria-describedby="mx_ServerPickerDialog"
12+
aria-labelledby="mx_BaseDialog_title"
13+
class="mx_ServerPickerDialog"
14+
data-focus-lock-disabled="false"
15+
role="dialog"
16+
>
17+
<div
18+
class="mx_Dialog_header mx_Dialog_headerWithCancel"
19+
>
20+
<h2
21+
class="mx_Heading_h2 mx_Dialog_title"
22+
id="mx_BaseDialog_title"
23+
>
24+
Sign into your homeserver
25+
</h2>
26+
<div
27+
aria-label="Close dialog"
28+
class="mx_AccessibleButton mx_Dialog_cancelButton"
29+
role="button"
30+
tabindex="0"
31+
/>
32+
</div>
33+
<form
34+
class="mx_Dialog_content"
35+
id="mx_ServerPickerDialog"
36+
>
37+
<p>
38+
We call the places where you can host your account 'homeservers'.
39+
40+
Matrix.org is the biggest public homeserver in the world, so it's a good place for many.
41+
</p>
42+
<label
43+
class="mx_StyledRadioButton mx_StyledRadioButton_enabled"
44+
>
45+
<input
46+
checked=""
47+
data-testid="defaultHomeserver"
48+
name="defaultChosen"
49+
type="radio"
50+
value="true"
51+
/>
52+
<div>
53+
<div />
54+
</div>
55+
<div
56+
class="mx_StyledRadioButton_content"
57+
>
58+
<div
59+
aria-describedby="mx_TooltipTarget_abdefghi"
60+
class="mx_TextWithTooltip_target mx_Login_underlinedServerName"
61+
tabindex="0"
62+
>
63+
matrix.org
64+
</div>
65+
</div>
66+
<div
67+
class="mx_StyledRadioButton_spacer"
68+
/>
69+
</label>
70+
<div
71+
class="mx_StyledRadioButton mx_ServerPickerDialog_otherHomeserverRadio mx_StyledRadioButton_enabled mx_StyledRadioButton_checked"
72+
>
73+
<label
74+
class="mx_StyledRadioButton_innerLabel"
75+
>
76+
<input
77+
aria-label="Other homeserver"
78+
name="defaultChosen"
79+
type="radio"
80+
value="false"
81+
/>
82+
<div>
83+
<div />
84+
</div>
85+
</label>
86+
<div
87+
class="mx_StyledRadioButton_content"
88+
>
89+
<div
90+
class="mx_Field mx_Field_input mx_ServerPickerDialog_otherHomeserver"
91+
>
92+
<input
93+
id="mx_homeserverInput"
94+
label="Other homeserver"
95+
placeholder="Other homeserver"
96+
type="text"
97+
value=""
98+
/>
99+
<label
100+
for="mx_homeserverInput"
101+
>
102+
Other homeserver
103+
</label>
104+
</div>
105+
</div>
106+
<div
107+
class="mx_StyledRadioButton_spacer"
108+
/>
109+
</div>
110+
<p>
111+
Use your preferred Matrix homeserver if you have one, or host your own.
112+
</p>
113+
<div
114+
class="mx_AccessibleButton mx_ServerPickerDialog_continue mx_AccessibleButton_hasKind mx_AccessibleButton_kind_primary"
115+
role="button"
116+
tabindex="0"
117+
>
118+
Continue
119+
</div>
120+
<h2>
121+
Learn more
122+
</h2>
123+
<a
124+
class="mx_ExternalLink"
125+
href="https://matrix.org/faq/#what-is-a-homeserver%3F"
126+
rel="noreferrer noopener"
127+
target="_blank"
128+
>
129+
About homeservers
130+
<i
131+
class="mx_ExternalLink_icon"
132+
/>
133+
</a>
134+
</form>
135+
</div>
136+
<div
137+
data-focus-guard="true"
138+
style="width: 1px; height: 0px; padding: 0px; overflow: hidden; position: fixed; top: 1px; left: 1px;"
139+
tabindex="0"
140+
/>
141+
</div>
142+
`;

0 commit comments

Comments
 (0)