-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(lowercase-invite): automatically lowercase field text in invite …
…input
- Loading branch information
marc.sirisak
committed
Jun 17, 2024
1 parent
6be037d
commit 81796e8
Showing
5 changed files
with
217 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
198 changes: 198 additions & 0 deletions
198
test/unit-tests/tchap/components/views/dialogs/InviteDialog-test.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,198 @@ | ||
import React from "react"; | ||
import { render, screen } from "@testing-library/react"; | ||
import userEvent from "@testing-library/user-event"; | ||
import { MatrixClient, MatrixError, Room } from "matrix-js-sdk/src/matrix"; | ||
import { Mocked } from "jest-mock"; | ||
|
||
import InviteDialog from "~matrix-react-sdk/src/components/views/dialogs/InviteDialog"; | ||
import { InviteKind } from "~matrix-react-sdk/src/components/views/dialogs/InviteDialogTypes"; | ||
import DMRoomMap from "~matrix-react-sdk/src/utils/DMRoomMap"; | ||
import SdkConfig from "~matrix-react-sdk/src/SdkConfig"; | ||
import { ValidatedServerConfig } from "~matrix-react-sdk/src/utils/ValidatedServerConfig"; | ||
import { IConfigOptions } from "~matrix-react-sdk/src/IConfigOptions"; | ||
import { SdkContextClass } from "~matrix-react-sdk/src/contexts/SDKContext"; | ||
import { IProfileInfo } from "~matrix-react-sdk/src/hooks/useProfileInfo"; | ||
import Modal from "~matrix-react-sdk/src/Modal"; | ||
import { | ||
filterConsole, | ||
flushPromises, | ||
getMockClientWithEventEmitter | ||
} from "~matrix-react-sdk/test/test-utils"; | ||
|
||
const getSearchField = () => screen.getByTestId("invite-dialog-input"); | ||
|
||
const enterIntoSearchField = async (value: string) => { | ||
const searchField = getSearchField(); | ||
await userEvent.clear(searchField); | ||
await userEvent.type(searchField, value + "{enter}"); | ||
}; | ||
|
||
const pasteIntoSearchField = async (value: string) => { | ||
const searchField = getSearchField(); | ||
await userEvent.clear(searchField); | ||
searchField.focus(); | ||
await userEvent.paste(value); | ||
await userEvent.type(searchField, value + "{enter}"); | ||
}; | ||
|
||
|
||
const roomId = "!111111111111111111:example.org"; | ||
const aliceId = "@alice:example.org"; | ||
const aliceEmail = "[email protected]"; | ||
const aliceUppercaseEmail = "[email protected]"; | ||
|
||
|
||
const aliceProfileInfo: IProfileInfo = { | ||
user_id: aliceId, | ||
display_name: "Alice", | ||
}; | ||
|
||
const bobId = "@bob:example.org"; | ||
const bobProfileInfo: IProfileInfo = { | ||
user_id: bobId, | ||
display_name: "Bob", | ||
}; | ||
|
||
describe("InviteDialog", () => { | ||
let mockClient: Mocked<MatrixClient>; | ||
let room: Room; | ||
|
||
filterConsole( | ||
"Error retrieving profile for userId @carol:example.com", | ||
"Error retrieving profile for userId @localpart:server.tld", | ||
"Error retrieving profile for userId @localpart:server:tld", | ||
"[Invite:Recents] Excluding @alice:example.org from recents", | ||
); | ||
|
||
beforeEach(() => { | ||
mockClient = getMockClientWithEventEmitter({ | ||
getUserId: jest.fn().mockReturnValue(bobId), | ||
getSafeUserId: jest.fn().mockReturnValue(bobId), | ||
isGuest: jest.fn().mockReturnValue(false), | ||
getVisibleRooms: jest.fn().mockReturnValue([]), | ||
getRoom: jest.fn(), | ||
getRooms: jest.fn(), | ||
getAccountData: jest.fn(), | ||
getPushActionsForEvent: jest.fn(), | ||
mxcUrlToHttp: jest.fn().mockReturnValue(""), | ||
isRoomEncrypted: jest.fn().mockReturnValue(false), | ||
getProfileInfo: jest.fn().mockImplementation(async (userId: string) => { | ||
if (userId === aliceId) return aliceProfileInfo; | ||
if (userId === bobId) return bobProfileInfo; | ||
|
||
throw new MatrixError({ | ||
errcode: "M_NOT_FOUND", | ||
error: "Profile not found", | ||
}); | ||
}), | ||
getIdentityServerUrl: jest.fn(), | ||
searchUserDirectory: jest.fn().mockResolvedValue({}), | ||
lookupThreePid: jest.fn(), | ||
registerWithIdentityServer: jest.fn().mockResolvedValue({ | ||
access_token: "access_token", | ||
token: "token", | ||
}), | ||
getOpenIdToken: jest.fn().mockResolvedValue({}), | ||
getIdentityAccount: jest.fn().mockResolvedValue({}), | ||
getTerms: jest.fn().mockResolvedValue({ policies: [] }), | ||
supportsThreads: jest.fn().mockReturnValue(false), | ||
isInitialSyncComplete: jest.fn().mockReturnValue(true), | ||
getClientWellKnown: jest.fn().mockResolvedValue({}), | ||
}); | ||
SdkConfig.put({ validated_server_config: {} as ValidatedServerConfig } as IConfigOptions); | ||
DMRoomMap.makeShared(mockClient); | ||
jest.clearAllMocks(); | ||
|
||
room = new Room(roomId, mockClient, mockClient.getSafeUserId()); | ||
|
||
jest.spyOn(DMRoomMap.shared(), "getUniqueRoomsWithIndividuals").mockReturnValue({ | ||
[aliceId]: room, | ||
}); | ||
mockClient.getRooms.mockReturnValue([room]); | ||
mockClient.getRoom.mockReturnValue(room); | ||
|
||
SdkContextClass.instance.client = mockClient; | ||
}); | ||
|
||
afterEach(() => { | ||
Modal.closeCurrentModal(); | ||
SdkContextClass.instance.onLoggedOut(); | ||
SdkContextClass.instance.client = undefined; | ||
}); | ||
|
||
afterAll(() => { | ||
jest.restoreAllMocks(); | ||
}); | ||
|
||
|
||
it("should entered values as lowercase", async () => { | ||
mockClient.getIdentityServerUrl.mockReturnValue("https://identity-server"); | ||
mockClient.lookupThreePid.mockResolvedValue({}); | ||
|
||
render(<InviteDialog kind={InviteKind.Invite} roomId={roomId} onFinished={jest.fn()} />); | ||
|
||
const input = getSearchField(); | ||
input.focus(); | ||
|
||
// Type and enter | ||
await enterIntoSearchField(aliceUppercaseEmail); | ||
|
||
// Because it has been transoformed to lowercase, it shoyld not be found in the document | ||
expect(screen.queryByText(aliceUppercaseEmail)).not.toBeInTheDocument(); | ||
|
||
expect(screen.queryByText(aliceEmail)).toBeInTheDocument(); | ||
|
||
// If it was transformed correctly to a pill, the input should have no value | ||
expect(input).toHaveValue(""); | ||
}); | ||
|
||
it("should add pasted email values as lowercase", async () => { | ||
mockClient.getIdentityServerUrl.mockReturnValue("https://identity-server"); | ||
mockClient.lookupThreePid.mockResolvedValue({}); | ||
|
||
render(<InviteDialog kind={InviteKind.Invite} roomId={roomId} onFinished={jest.fn()} />); | ||
|
||
// Juste paste some values without enter | ||
await pasteIntoSearchField(aliceUppercaseEmail); | ||
|
||
await flushPromises(); | ||
|
||
// Because it has been transoformed to lowercase, it shoyld not be found in the document | ||
expect(screen.queryByText(aliceUppercaseEmail)).not.toBeInTheDocument(); | ||
|
||
// contrary to the entered values, on this paste test we don't enter, so we have multiple result | ||
expect(screen.queryAllByText(aliceEmail)[0]).toBeInTheDocument(); | ||
|
||
}); | ||
|
||
|
||
it("should not crash if empty values are entered", async () => { | ||
mockClient.getIdentityServerUrl.mockReturnValue("https://identity-server"); | ||
mockClient.lookupThreePid.mockResolvedValue({}); | ||
|
||
render(<InviteDialog kind={InviteKind.Invite} roomId={roomId} onFinished={jest.fn()} />); | ||
|
||
const input = getSearchField(); | ||
input.focus(); | ||
|
||
// Type and enter | ||
await enterIntoSearchField(""); | ||
|
||
expect(input).toHaveValue(""); | ||
|
||
}) | ||
|
||
it("should not crash if empty values are pasted", async () => { | ||
mockClient.getIdentityServerUrl.mockReturnValue("https://identity-server"); | ||
mockClient.lookupThreePid.mockResolvedValue({}); | ||
|
||
render(<InviteDialog kind={InviteKind.Invite} roomId={roomId} onFinished={jest.fn()} />); | ||
const input = getSearchField(); | ||
|
||
// Juste paste some values without enter | ||
await pasteIntoSearchField(""); | ||
|
||
expect(input).toHaveValue(""); | ||
}) | ||
|
||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters