mirror of
https://github.com/element-hq/element-web
synced 2024-11-22 17:25:50 +03:00
Convert spotlight tests to playwright (#12033)
* Convert tests * Use existing code * Remove code from settings * Change names * Change comment * Update comment
This commit is contained in:
parent
7508e62eda
commit
d1562befc4
3 changed files with 408 additions and 460 deletions
|
@ -1,458 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright 2022 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/// <reference types="cypress" />
|
|
||||||
|
|
||||||
import { MatrixClient } from "../../global";
|
|
||||||
import { HomeserverInstance } from "../../plugins/utils/homeserver";
|
|
||||||
import Chainable = Cypress.Chainable;
|
|
||||||
import Loggable = Cypress.Loggable;
|
|
||||||
import Timeoutable = Cypress.Timeoutable;
|
|
||||||
import Withinable = Cypress.Withinable;
|
|
||||||
import Shadow = Cypress.Shadow;
|
|
||||||
import { Filter } from "../../support/settings";
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-namespace
|
|
||||||
namespace Cypress {
|
|
||||||
interface Chainable {
|
|
||||||
roomHeaderName(
|
|
||||||
options?: Partial<Loggable & Timeoutable & Withinable & Shadow>,
|
|
||||||
): Chainable<JQuery<HTMLElement>>;
|
|
||||||
startDM(name: string): Chainable<void>;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Cypress.Commands.add(
|
|
||||||
"roomHeaderName",
|
|
||||||
(options?: Partial<Loggable & Timeoutable & Withinable & Shadow>): Chainable<JQuery<HTMLElement>> => {
|
|
||||||
return cy.get(".mx_LegacyRoomHeader_nametext", options);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
Cypress.Commands.add("startDM", (name: string) => {
|
|
||||||
cy.openSpotlightDialog().within(() => {
|
|
||||||
cy.spotlightFilter(Filter.People);
|
|
||||||
cy.spotlightSearch().clear().type(name);
|
|
||||||
cy.wait(1000); // wait for the dialog code to settle
|
|
||||||
cy.get(".mx_Spinner").should("not.exist");
|
|
||||||
cy.spotlightResults().should("have.length", 1);
|
|
||||||
cy.spotlightResults().eq(0).should("contain", name);
|
|
||||||
cy.spotlightResults().eq(0).click();
|
|
||||||
});
|
|
||||||
// send first message to start DM
|
|
||||||
cy.findByRole("textbox", { name: "Send a message…" }).should("have.focus").type("Hey!{enter}");
|
|
||||||
// The DM room is created at this point, this can take a little bit of time
|
|
||||||
cy.get(".mx_EventTile_body", { timeout: 30000 }).findByText("Hey!");
|
|
||||||
cy.findByRole("group", { name: "People" }).findByText(name);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("Spotlight", () => {
|
|
||||||
let homeserver: HomeserverInstance;
|
|
||||||
|
|
||||||
const bot1Name = "BotBob";
|
|
||||||
let bot1: MatrixClient;
|
|
||||||
|
|
||||||
const bot2Name = "ByteBot";
|
|
||||||
let bot2: MatrixClient;
|
|
||||||
|
|
||||||
const room1Name = "247";
|
|
||||||
let room1Id: string;
|
|
||||||
|
|
||||||
const room2Name = "Lounge";
|
|
||||||
let room2Id: string;
|
|
||||||
|
|
||||||
const room3Name = "Public";
|
|
||||||
let room3Id: string;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
cy.startHomeserver("default").then((data) => {
|
|
||||||
homeserver = data;
|
|
||||||
cy.initTestUser(homeserver, "Jim")
|
|
||||||
.then(() =>
|
|
||||||
cy.getBot(homeserver, { displayName: bot1Name }).then((_bot1) => {
|
|
||||||
bot1 = _bot1;
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
.then(() =>
|
|
||||||
cy.getBot(homeserver, { displayName: bot2Name }).then((_bot2) => {
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
||||||
bot2 = _bot2;
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
.then(() =>
|
|
||||||
cy.window({ log: false }).then(({ matrixcs: { Visibility } }) => {
|
|
||||||
cy.createRoom({ name: room1Name, visibility: Visibility.Public }).then(async (_room1Id) => {
|
|
||||||
room1Id = _room1Id;
|
|
||||||
await bot1.joinRoom(room1Id);
|
|
||||||
});
|
|
||||||
bot2.createRoom({ name: room2Name, visibility: Visibility.Public }).then(
|
|
||||||
({ room_id: _room2Id }) => {
|
|
||||||
room2Id = _room2Id;
|
|
||||||
bot2.invite(room2Id, bot1.getUserId());
|
|
||||||
},
|
|
||||||
);
|
|
||||||
bot2.createRoom({
|
|
||||||
name: room3Name,
|
|
||||||
visibility: Visibility.Public,
|
|
||||||
initial_state: [
|
|
||||||
{
|
|
||||||
type: "m.room.history_visibility",
|
|
||||||
state_key: "",
|
|
||||||
content: {
|
|
||||||
history_visibility: "world_readable",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}).then(({ room_id: _room3Id }) => {
|
|
||||||
room3Id = _room3Id;
|
|
||||||
bot2.invite(room3Id, bot1.getUserId());
|
|
||||||
});
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
.then(() => {
|
|
||||||
cy.visit("/#/room/" + room1Id);
|
|
||||||
cy.get(".mx_RoomSublist_skeletonUI").should("not.exist");
|
|
||||||
});
|
|
||||||
});
|
|
||||||
// wait for the room to have the right name
|
|
||||||
cy.get(".mx_LegacyRoomHeader").within(() => {
|
|
||||||
cy.findByText(room1Name);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
cy.visit("/#/home");
|
|
||||||
cy.stopHomeserver(homeserver);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should be able to add and remove filters via keyboard", () => {
|
|
||||||
cy.openSpotlightDialog().within(() => {
|
|
||||||
cy.wait(1000); // wait for the dialog to settle, otherwise our keypresses might race with an update
|
|
||||||
|
|
||||||
// initially, public spaces should be highlighted (because there are no other suggestions)
|
|
||||||
cy.get("#mx_SpotlightDialog_button_explorePublicSpaces").should("have.attr", "aria-selected", "true");
|
|
||||||
|
|
||||||
// hitting enter should enable the public rooms filter
|
|
||||||
cy.spotlightSearch().type("{enter}");
|
|
||||||
cy.get(".mx_SpotlightDialog_filter").should("contain", "Public spaces");
|
|
||||||
cy.spotlightSearch().type("{backspace}");
|
|
||||||
cy.get(".mx_SpotlightDialog_filter").should("not.exist");
|
|
||||||
cy.wait(200); // Again, wait to settle so keypresses arrive correctly
|
|
||||||
|
|
||||||
cy.spotlightSearch().type("{downArrow}");
|
|
||||||
cy.get("#mx_SpotlightDialog_button_explorePublicRooms").should("have.attr", "aria-selected", "true");
|
|
||||||
cy.spotlightSearch().type("{enter}");
|
|
||||||
cy.get(".mx_SpotlightDialog_filter").should("contain", "Public rooms");
|
|
||||||
cy.spotlightSearch().type("{backspace}");
|
|
||||||
cy.get(".mx_SpotlightDialog_filter").should("not.exist");
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should find joined rooms", () => {
|
|
||||||
cy.openSpotlightDialog()
|
|
||||||
.within(() => {
|
|
||||||
cy.wait(500); // Wait for dialog to settle
|
|
||||||
cy.spotlightSearch().clear().type(room1Name);
|
|
||||||
cy.spotlightResults().should("have.length", 1);
|
|
||||||
cy.spotlightResults().eq(0).should("contain", room1Name);
|
|
||||||
cy.spotlightResults().eq(0).click();
|
|
||||||
cy.url().should("contain", room1Id);
|
|
||||||
})
|
|
||||||
.then(() => {
|
|
||||||
cy.roomHeaderName().should("contain", room1Name);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should find known public rooms", () => {
|
|
||||||
cy.openSpotlightDialog()
|
|
||||||
.within(() => {
|
|
||||||
cy.wait(500); // Wait for dialog to settle
|
|
||||||
cy.spotlightFilter(Filter.PublicRooms);
|
|
||||||
cy.spotlightSearch().clear().type(room1Name);
|
|
||||||
cy.spotlightResults().should("have.length", 1);
|
|
||||||
cy.spotlightResults().eq(0).should("contain", room1Name);
|
|
||||||
cy.spotlightResults().eq(0).should("contain", "View");
|
|
||||||
cy.spotlightResults().eq(0).click();
|
|
||||||
cy.url().should("contain", room1Id);
|
|
||||||
})
|
|
||||||
.then(() => {
|
|
||||||
cy.roomHeaderName().should("contain", room1Name);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should find unknown public rooms", () => {
|
|
||||||
cy.openSpotlightDialog()
|
|
||||||
.within(() => {
|
|
||||||
cy.wait(500); // Wait for dialog to settle
|
|
||||||
cy.spotlightFilter(Filter.PublicRooms);
|
|
||||||
cy.spotlightSearch().clear().type(room2Name);
|
|
||||||
cy.spotlightResults().should("have.length", 1);
|
|
||||||
cy.spotlightResults().eq(0).should("contain", room2Name);
|
|
||||||
cy.spotlightResults().eq(0).should("contain", "Join");
|
|
||||||
cy.spotlightResults().eq(0).click();
|
|
||||||
cy.url().should("contain", room2Id);
|
|
||||||
})
|
|
||||||
.then(() => {
|
|
||||||
cy.get(".mx_RoomView_MessageList").should("have.length", 1);
|
|
||||||
cy.roomHeaderName().should("contain", room2Name);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should find unknown public world readable rooms", () => {
|
|
||||||
cy.openSpotlightDialog()
|
|
||||||
.within(() => {
|
|
||||||
cy.wait(500); // Wait for dialog to settle
|
|
||||||
cy.spotlightFilter(Filter.PublicRooms);
|
|
||||||
cy.spotlightSearch().clear().type(room3Name);
|
|
||||||
cy.spotlightResults().should("have.length", 1);
|
|
||||||
cy.spotlightResults().eq(0).should("contain", room3Name);
|
|
||||||
cy.spotlightResults().eq(0).should("contain", "View");
|
|
||||||
cy.spotlightResults().eq(0).click();
|
|
||||||
cy.url().should("contain", room3Id);
|
|
||||||
})
|
|
||||||
.then(() => {
|
|
||||||
cy.findByRole("button", { name: "Join the discussion" }).click();
|
|
||||||
cy.roomHeaderName().should("contain", room3Name);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// TODO: We currently can’t test finding rooms on other homeservers/other protocols
|
|
||||||
// We obviously don’t have federation or bridges in cypress tests
|
|
||||||
it.skip("should find unknown public rooms on other homeservers", () => {
|
|
||||||
cy.openSpotlightDialog()
|
|
||||||
.within(() => {
|
|
||||||
cy.wait(500); // Wait for dialog to settle
|
|
||||||
cy.spotlightFilter(Filter.PublicRooms);
|
|
||||||
cy.spotlightSearch().clear().type(room3Name);
|
|
||||||
cy.get("[aria-haspopup=true][role=button]").click();
|
|
||||||
})
|
|
||||||
.then(() => {
|
|
||||||
cy.contains(".mx_GenericDropdownMenu_Option--header", "matrix.org")
|
|
||||||
.next("[role=menuitemradio]")
|
|
||||||
.click();
|
|
||||||
cy.wait(3_600_000);
|
|
||||||
})
|
|
||||||
.then(() =>
|
|
||||||
cy.spotlightDialog().within(() => {
|
|
||||||
cy.wait(500); // Wait for dialog to settle
|
|
||||||
cy.spotlightResults().should("have.length", 1);
|
|
||||||
cy.spotlightResults().eq(0).should("contain", room3Name);
|
|
||||||
cy.spotlightResults().eq(0).should("contain", room3Id);
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should find known people", () => {
|
|
||||||
cy.openSpotlightDialog()
|
|
||||||
.within(() => {
|
|
||||||
cy.wait(500); // Wait for dialog to settle
|
|
||||||
cy.spotlightFilter(Filter.People);
|
|
||||||
cy.spotlightSearch().clear().type(bot1Name);
|
|
||||||
cy.spotlightResults().should("have.length", 1);
|
|
||||||
cy.spotlightResults().eq(0).should("contain", bot1Name);
|
|
||||||
cy.spotlightResults().eq(0).click();
|
|
||||||
})
|
|
||||||
.then(() => {
|
|
||||||
cy.roomHeaderName().should("contain", bot1Name);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Search sends the correct query to Synapse.
|
|
||||||
* Synapse doesn't return the user in the result list.
|
|
||||||
* Waiting for the profile to be available via APIs before the tests didn't help.
|
|
||||||
*
|
|
||||||
* https://github.com/matrix-org/synapse/issues/16472
|
|
||||||
*/
|
|
||||||
it.skip("should find unknown people", () => {
|
|
||||||
cy.openSpotlightDialog()
|
|
||||||
.within(() => {
|
|
||||||
cy.wait(500); // Wait for dialog to settle
|
|
||||||
cy.spotlightFilter(Filter.People);
|
|
||||||
cy.spotlightSearch().clear().type(bot2Name);
|
|
||||||
cy.spotlightResults().should("have.length", 1);
|
|
||||||
cy.spotlightResults().eq(0).should("contain", bot2Name);
|
|
||||||
cy.spotlightResults().eq(0).click();
|
|
||||||
})
|
|
||||||
.then(() => {
|
|
||||||
cy.roomHeaderName().should("contain", bot2Name);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should find group DMs by usernames or user ids", () => {
|
|
||||||
// First we want to share a room with both bots to ensure we’ve got their usernames cached
|
|
||||||
cy.inviteUser(room1Id, bot2.getUserId());
|
|
||||||
|
|
||||||
// Starting a DM with ByteBot (will be turned into a group dm later)
|
|
||||||
cy.openSpotlightDialog().within(() => {
|
|
||||||
cy.wait(500); // Wait for dialog to settle
|
|
||||||
cy.spotlightFilter(Filter.People);
|
|
||||||
cy.spotlightSearch().clear().type(bot2Name);
|
|
||||||
cy.spotlightResults().should("have.length", 1);
|
|
||||||
cy.spotlightResults().eq(0).should("contain", bot2Name);
|
|
||||||
cy.spotlightResults().eq(0).click();
|
|
||||||
});
|
|
||||||
|
|
||||||
// Send first message to actually start DM
|
|
||||||
cy.roomHeaderName().should("contain", bot2Name);
|
|
||||||
cy.findByRole("textbox", { name: "Send a message…" }).type("Hey!{enter}");
|
|
||||||
|
|
||||||
// Assert DM exists by checking for the first message and the room being in the room list
|
|
||||||
cy.contains(".mx_EventTile_body", "Hey!", { timeout: 30000 });
|
|
||||||
cy.findByRole("group", { name: "People" }).should("contain", bot2Name);
|
|
||||||
|
|
||||||
// Invite BotBob into existing DM with ByteBot
|
|
||||||
cy.getDmRooms(bot2.getUserId())
|
|
||||||
.should("have.length", 1)
|
|
||||||
.then((dmRooms) => cy.getClient().then((client) => client.getRoom(dmRooms[0])))
|
|
||||||
.then((groupDm) => {
|
|
||||||
cy.inviteUser(groupDm.roomId, bot1.getUserId());
|
|
||||||
cy.roomHeaderName().should(($element) => expect($element.get(0).innerText).contains(groupDm.name));
|
|
||||||
cy.findByRole("group", { name: "People" }).should(($element) =>
|
|
||||||
expect($element.get(0).innerText).contains(groupDm.name),
|
|
||||||
);
|
|
||||||
|
|
||||||
// Search for BotBob by id, should return group DM and user
|
|
||||||
cy.openSpotlightDialog().within(() => {
|
|
||||||
cy.spotlightFilter(Filter.People);
|
|
||||||
cy.spotlightSearch().clear().type(bot1.getUserId());
|
|
||||||
cy.wait(1000); // wait for the dialog code to settle
|
|
||||||
cy.spotlightResults().should("have.length", 2);
|
|
||||||
cy.contains(
|
|
||||||
".mx_SpotlightDialog_section.mx_SpotlightDialog_results .mx_SpotlightDialog_option",
|
|
||||||
groupDm.name,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Search for ByteBot by id, should return group DM and user
|
|
||||||
cy.openSpotlightDialog().within(() => {
|
|
||||||
cy.spotlightFilter(Filter.People);
|
|
||||||
cy.spotlightSearch().clear().type(bot2.getUserId());
|
|
||||||
cy.wait(1000); // wait for the dialog code to settle
|
|
||||||
cy.spotlightResults().should("have.length", 2);
|
|
||||||
cy.contains(
|
|
||||||
".mx_SpotlightDialog_section.mx_SpotlightDialog_results .mx_SpotlightDialog_option",
|
|
||||||
groupDm.name,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// Test against https://github.com/vector-im/element-web/issues/22851
|
|
||||||
it("should show each person result only once", () => {
|
|
||||||
cy.openSpotlightDialog().within(() => {
|
|
||||||
cy.wait(500); // Wait for dialog to settle
|
|
||||||
cy.spotlightFilter(Filter.People);
|
|
||||||
|
|
||||||
// 2 rounds of search to simulate the bug conditions. Specifically, the first search
|
|
||||||
// should have 1 result (not 2) and the second search should also have 1 result (instead
|
|
||||||
// of the super buggy 3 described by https://github.com/vector-im/element-web/issues/22851)
|
|
||||||
//
|
|
||||||
// We search for user ID to trigger the profile lookup within the dialog.
|
|
||||||
for (let i = 0; i < 2; i++) {
|
|
||||||
cy.log("Iteration: " + i);
|
|
||||||
cy.spotlightSearch().clear().type(bot1.getUserId());
|
|
||||||
cy.wait(1000); // wait for the dialog code to settle
|
|
||||||
cy.spotlightResults().should("have.length", 1);
|
|
||||||
cy.spotlightResults().eq(0).should("contain", bot1.getUserId());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should allow opening group chat dialog", () => {
|
|
||||||
cy.openSpotlightDialog()
|
|
||||||
.within(() => {
|
|
||||||
cy.wait(500); // Wait for dialog to settle
|
|
||||||
cy.spotlightFilter(Filter.People);
|
|
||||||
cy.spotlightSearch().clear().type(bot2Name);
|
|
||||||
cy.wait(3000); // wait for the dialog code to settle
|
|
||||||
cy.spotlightResults().should("have.length", 1);
|
|
||||||
cy.spotlightResults().eq(0).should("contain", bot2Name);
|
|
||||||
cy.get(".mx_SpotlightDialog_startGroupChat").should("contain", "Start a group chat");
|
|
||||||
cy.get(".mx_SpotlightDialog_startGroupChat").click();
|
|
||||||
})
|
|
||||||
.then(() => {
|
|
||||||
cy.findByRole("dialog").should("contain", "Direct Messages");
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should close spotlight after starting a DM", () => {
|
|
||||||
cy.startDM(bot1Name);
|
|
||||||
cy.get(".mx_SpotlightDialog").should("have.length", 0);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should show the same user only once", () => {
|
|
||||||
cy.startDM(bot1Name);
|
|
||||||
cy.visit("/#/home");
|
|
||||||
|
|
||||||
cy.openSpotlightDialog().within(() => {
|
|
||||||
cy.wait(500); // Wait for dialog to settle
|
|
||||||
cy.spotlightFilter(Filter.People);
|
|
||||||
cy.spotlightSearch().clear().type(bot1Name);
|
|
||||||
cy.wait(3000); // wait for the dialog code to settle
|
|
||||||
cy.get(".mx_Spinner").should("not.exist");
|
|
||||||
cy.spotlightResults().should("have.length", 1);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should be able to navigate results via keyboard", () => {
|
|
||||||
cy.openSpotlightDialog().within(() => {
|
|
||||||
cy.wait(500); // Wait for dialog to settle
|
|
||||||
cy.spotlightFilter(Filter.People);
|
|
||||||
cy.spotlightSearch().clear().type("b");
|
|
||||||
// our debouncing logic only starts the search after a short timeout,
|
|
||||||
// so we wait a few milliseconds.
|
|
||||||
cy.wait(1000);
|
|
||||||
cy.get(".mx_Spinner")
|
|
||||||
.should("not.exist")
|
|
||||||
.then(() => {
|
|
||||||
cy.wait(500); // Wait to settle again
|
|
||||||
cy.spotlightResults()
|
|
||||||
.should("have.length", 2)
|
|
||||||
.then(() => {
|
|
||||||
cy.spotlightResults().eq(0).should("have.attr", "aria-selected", "true");
|
|
||||||
cy.spotlightResults().eq(1).should("have.attr", "aria-selected", "false");
|
|
||||||
});
|
|
||||||
cy.spotlightSearch()
|
|
||||||
.type("{downArrow}")
|
|
||||||
.then(() => {
|
|
||||||
cy.spotlightResults().eq(0).should("have.attr", "aria-selected", "false");
|
|
||||||
cy.spotlightResults().eq(1).should("have.attr", "aria-selected", "true");
|
|
||||||
});
|
|
||||||
cy.spotlightSearch()
|
|
||||||
.type("{downArrow}")
|
|
||||||
.then(() => {
|
|
||||||
cy.spotlightResults().eq(0).should("have.attr", "aria-selected", "false");
|
|
||||||
cy.spotlightResults().eq(1).should("have.attr", "aria-selected", "false");
|
|
||||||
});
|
|
||||||
cy.spotlightSearch()
|
|
||||||
.type("{upArrow}")
|
|
||||||
.then(() => {
|
|
||||||
cy.spotlightResults().eq(0).should("have.attr", "aria-selected", "false");
|
|
||||||
cy.spotlightResults().eq(1).should("have.attr", "aria-selected", "true");
|
|
||||||
});
|
|
||||||
cy.spotlightSearch()
|
|
||||||
.type("{upArrow}")
|
|
||||||
.then(() => {
|
|
||||||
cy.spotlightResults().eq(0).should("have.attr", "aria-selected", "true");
|
|
||||||
cy.spotlightResults().eq(1).should("have.attr", "aria-selected", "false");
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
393
playwright/e2e/spotlight/spotlight.spec.ts
Normal file
393
playwright/e2e/spotlight/spotlight.spec.ts
Normal file
|
@ -0,0 +1,393 @@
|
||||||
|
/*
|
||||||
|
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 { test, expect } from "../../element-web-test";
|
||||||
|
import { Filter } from "../../pages/Spotlight";
|
||||||
|
import { Bot } from "../../pages/bot";
|
||||||
|
import type { Locator, Page } from "@playwright/test";
|
||||||
|
import type { ElementAppPage } from "../../pages/ElementAppPage";
|
||||||
|
|
||||||
|
function roomHeaderName(page: Page): Locator {
|
||||||
|
return page.locator(".mx_LegacyRoomHeader_nametext");
|
||||||
|
}
|
||||||
|
|
||||||
|
async function startDM(app: ElementAppPage, page: Page, name: string): Promise<void> {
|
||||||
|
const spotlight = await app.openSpotlight();
|
||||||
|
await spotlight.filter(Filter.People);
|
||||||
|
await spotlight.search(name);
|
||||||
|
await page.waitForTimeout(1000); // wait for the dialog code to settle
|
||||||
|
await expect(spotlight.dialog.locator(".mx_Spinner")).not.toBeAttached();
|
||||||
|
const result = spotlight.results;
|
||||||
|
await expect(result).toHaveCount(1);
|
||||||
|
await expect(result.first()).toContainText(name);
|
||||||
|
await result.first().click();
|
||||||
|
|
||||||
|
// send first message to start DM
|
||||||
|
const locator = page.getByRole("textbox", { name: "Send a message…" });
|
||||||
|
await expect(locator).toBeFocused();
|
||||||
|
await locator.fill("Hey!");
|
||||||
|
await locator.press("Enter");
|
||||||
|
// The DM room is created at this point, this can take a little bit of time
|
||||||
|
await expect(page.locator(".mx_EventTile_body").getByText("Hey!")).toBeAttached({ timeout: 3000 });
|
||||||
|
await expect(page.getByRole("group", { name: "People" }).getByText(name)).toBeAttached();
|
||||||
|
}
|
||||||
|
|
||||||
|
test.describe("Spotlight", () => {
|
||||||
|
const bot1Name = "BotBob";
|
||||||
|
let bot1: Bot;
|
||||||
|
|
||||||
|
const bot2Name = "ByteBot";
|
||||||
|
let bot2: Bot;
|
||||||
|
|
||||||
|
const room1Name = "247";
|
||||||
|
let room1Id: string;
|
||||||
|
|
||||||
|
const room2Name = "Lounge";
|
||||||
|
let room2Id: string;
|
||||||
|
|
||||||
|
const room3Name = "Public";
|
||||||
|
let room3Id: string;
|
||||||
|
|
||||||
|
test.use({
|
||||||
|
displayName: "Jim",
|
||||||
|
});
|
||||||
|
|
||||||
|
test.beforeEach(async ({ page, homeserver, app, user }) => {
|
||||||
|
bot1 = new Bot(page, homeserver, { displayName: bot1Name, autoAcceptInvites: true });
|
||||||
|
bot2 = new Bot(page, homeserver, { displayName: bot2Name, autoAcceptInvites: true });
|
||||||
|
const Visibility = await page.evaluate(() => (window as any).matrixcs.Visibility);
|
||||||
|
|
||||||
|
room1Id = await app.client.createRoom({ name: room1Name, visibility: Visibility.Public });
|
||||||
|
|
||||||
|
await bot1.joinRoom(room1Id);
|
||||||
|
const bot1UserId = await bot1.evaluate((client) => client.getUserId());
|
||||||
|
room2Id = await bot2.createRoom({ name: room2Name, visibility: Visibility.Public });
|
||||||
|
await bot2.inviteUser(room2Id, bot1UserId);
|
||||||
|
|
||||||
|
room3Id = await bot2.createRoom({
|
||||||
|
name: room3Name,
|
||||||
|
visibility: Visibility.Public,
|
||||||
|
initial_state: [
|
||||||
|
{
|
||||||
|
type: "m.room.history_visibility",
|
||||||
|
state_key: "",
|
||||||
|
content: {
|
||||||
|
history_visibility: "world_readable",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
await bot2.inviteUser(room3Id, bot1UserId);
|
||||||
|
|
||||||
|
await page.goto("/#/room/" + room1Id);
|
||||||
|
await expect(page.locator(".mx_RoomSublist_skeletonUI")).not.toBeAttached();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("should be able to add and remove filters via keyboard", async ({ page, app }) => {
|
||||||
|
const spotlight = await app.openSpotlight();
|
||||||
|
await page.waitForTimeout(1000); // wait for the dialog to settle, otherwise our keypresses might race with an update
|
||||||
|
|
||||||
|
// initially, public spaces should be highlighted (because there are no other suggestions)
|
||||||
|
await expect(spotlight.dialog.locator("#mx_SpotlightDialog_button_explorePublicSpaces")).toHaveAttribute(
|
||||||
|
"aria-selected",
|
||||||
|
"true",
|
||||||
|
);
|
||||||
|
|
||||||
|
// hitting enter should enable the public rooms filter
|
||||||
|
await spotlight.searchBox.press("Enter");
|
||||||
|
await expect(spotlight.dialog.locator(".mx_SpotlightDialog_filter")).toHaveText("Public spaces");
|
||||||
|
await spotlight.searchBox.press("Backspace");
|
||||||
|
await expect(spotlight.dialog.locator(".mx_SpotlightDialog_filter")).not.toBeAttached();
|
||||||
|
await page.waitForTimeout(200); // Again, wait to settle so keypresses arrive correctly
|
||||||
|
|
||||||
|
await spotlight.searchBox.press("ArrowDown");
|
||||||
|
await expect(spotlight.dialog.locator("#mx_SpotlightDialog_button_explorePublicRooms")).toHaveAttribute(
|
||||||
|
"aria-selected",
|
||||||
|
"true",
|
||||||
|
);
|
||||||
|
await spotlight.searchBox.press("Enter");
|
||||||
|
await expect(spotlight.dialog.locator(".mx_SpotlightDialog_filter")).toHaveText("Public rooms");
|
||||||
|
await spotlight.searchBox.press("Backspace");
|
||||||
|
await expect(spotlight.dialog.locator(".mx_SpotlightDialog_filter")).not.toBeAttached();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("should find joined rooms", async ({ page, app }) => {
|
||||||
|
const spotlight = await app.openSpotlight();
|
||||||
|
await page.waitForTimeout(500); // wait for the dialog to settle
|
||||||
|
await spotlight.search(room1Name);
|
||||||
|
const resultLocator = spotlight.results;
|
||||||
|
await expect(resultLocator).toHaveCount(1);
|
||||||
|
await expect(resultLocator.first()).toContainText(room1Name);
|
||||||
|
await resultLocator.first().click();
|
||||||
|
expect(page.url()).toContain(room1Id);
|
||||||
|
await expect(roomHeaderName(page)).toContainText(room1Name);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("should find known public rooms", async ({ page, app }) => {
|
||||||
|
const spotlight = await app.openSpotlight();
|
||||||
|
await page.waitForTimeout(500); // wait for the dialog to settle
|
||||||
|
await spotlight.filter(Filter.PublicRooms);
|
||||||
|
await spotlight.search(room1Name);
|
||||||
|
const resultLocator = spotlight.results;
|
||||||
|
await expect(resultLocator).toHaveCount(1);
|
||||||
|
await expect(resultLocator.first()).toContainText(room1Name);
|
||||||
|
await expect(resultLocator.first()).toContainText("View");
|
||||||
|
await resultLocator.first().click();
|
||||||
|
expect(page.url()).toContain(room1Id);
|
||||||
|
await expect(roomHeaderName(page)).toContainText(room1Name);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("should find unknown public rooms", async ({ page, app }) => {
|
||||||
|
const spotlight = await app.openSpotlight();
|
||||||
|
await page.waitForTimeout(500); // wait for the dialog to settle
|
||||||
|
await spotlight.filter(Filter.PublicRooms);
|
||||||
|
await spotlight.search(room2Name);
|
||||||
|
const resultLocator = spotlight.results;
|
||||||
|
await expect(resultLocator).toHaveCount(1);
|
||||||
|
await expect(resultLocator.first()).toContainText(room2Name);
|
||||||
|
await expect(resultLocator.first()).toContainText("Join");
|
||||||
|
await resultLocator.first().click();
|
||||||
|
expect(page.url()).toContain(room2Id);
|
||||||
|
await expect(page.locator(".mx_RoomView_MessageList")).toHaveCount(1);
|
||||||
|
await expect(roomHeaderName(page)).toContainText(room2Name);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("should find unknown public world readable rooms", async ({ page, app }) => {
|
||||||
|
const spotlight = await app.openSpotlight();
|
||||||
|
await page.waitForTimeout(500); // wait for the dialog to settle
|
||||||
|
await spotlight.filter(Filter.PublicRooms);
|
||||||
|
await spotlight.search(room3Name);
|
||||||
|
const resultLocator = spotlight.results;
|
||||||
|
await expect(resultLocator).toHaveCount(1);
|
||||||
|
await expect(resultLocator.first()).toContainText(room3Name);
|
||||||
|
await expect(resultLocator.first()).toContainText("View");
|
||||||
|
await resultLocator.first().click();
|
||||||
|
expect(page.url()).toContain(room3Id);
|
||||||
|
await page.getByRole("button", { name: "Join the discussion" }).click();
|
||||||
|
await expect(roomHeaderName(page)).toHaveText(room3Name);
|
||||||
|
});
|
||||||
|
|
||||||
|
// TODO: We currently can’t test finding rooms on other homeservers/other protocols
|
||||||
|
// We obviously don’t have federation or bridges in local e2e tests
|
||||||
|
test.skip("should find unknown public rooms on other homeservers", async ({ page, app }) => {
|
||||||
|
const spotlight = await app.openSpotlight();
|
||||||
|
await page.waitForTimeout(500); // wait for the dialog to settle
|
||||||
|
await spotlight.filter(Filter.PublicRooms);
|
||||||
|
await spotlight.search(room3Name);
|
||||||
|
await page.locator("[aria-haspopup=true][role=button]").click();
|
||||||
|
|
||||||
|
await page
|
||||||
|
.locator(".mx_GenericDropdownMenu_Option--header")
|
||||||
|
.filter({ hasText: "matrix.org" })
|
||||||
|
.locator("..")
|
||||||
|
.locator("[role=menuitemradio]")
|
||||||
|
.click();
|
||||||
|
await page.waitForTimeout(3_600_000);
|
||||||
|
|
||||||
|
await page.waitForTimeout(500); // wait for the dialog to settle
|
||||||
|
|
||||||
|
const resultLocator = spotlight.results;
|
||||||
|
await expect(resultLocator).toHaveCount(1);
|
||||||
|
await expect(resultLocator.first()).toContainText(room3Name);
|
||||||
|
await expect(resultLocator.first()).toContainText(room3Id);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("should find known people", async ({ page, app }) => {
|
||||||
|
const spotlight = await app.openSpotlight();
|
||||||
|
await page.waitForTimeout(500); // wait for the dialog to settle
|
||||||
|
await spotlight.filter(Filter.People);
|
||||||
|
await spotlight.search(bot1Name);
|
||||||
|
const resultLocator = spotlight.results;
|
||||||
|
await expect(resultLocator).toHaveCount(1);
|
||||||
|
await expect(resultLocator.first()).toContainText(bot1Name);
|
||||||
|
await resultLocator.first().click();
|
||||||
|
await expect(roomHeaderName(page)).toHaveText(bot1Name);
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Search sends the correct query to Synapse.
|
||||||
|
* Synapse doesn't return the user in the result list.
|
||||||
|
* Waiting for the profile to be available via APIs before the tests didn't help.
|
||||||
|
*
|
||||||
|
* https://github.com/matrix-org/synapse/issues/16472
|
||||||
|
*/
|
||||||
|
test.skip("should find unknown people", async ({ page, app }) => {
|
||||||
|
const spotlight = await app.openSpotlight();
|
||||||
|
await page.waitForTimeout(500); // wait for the dialog to settle
|
||||||
|
await spotlight.filter(Filter.People);
|
||||||
|
await spotlight.search(bot2Name);
|
||||||
|
const resultLocator = spotlight.results;
|
||||||
|
await expect(resultLocator).toHaveCount(1);
|
||||||
|
await expect(resultLocator.first()).toContainText(bot2Name);
|
||||||
|
await resultLocator.first().click();
|
||||||
|
await expect(roomHeaderName(page)).toHaveText(bot2Name);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("should find group DMs by usernames or user ids", async ({ page, app }) => {
|
||||||
|
// First we want to share a room with both bots to ensure we’ve got their usernames cached
|
||||||
|
const bot2UserId = await bot2.evaluate((client) => client.getUserId());
|
||||||
|
await app.client.inviteUser(room1Id, bot2UserId);
|
||||||
|
|
||||||
|
// Starting a DM with ByteBot (will be turned into a group dm later)
|
||||||
|
let spotlight = await app.openSpotlight();
|
||||||
|
await page.waitForTimeout(500); // wait for the dialog to settle
|
||||||
|
await spotlight.filter(Filter.People);
|
||||||
|
await spotlight.search(bot2Name);
|
||||||
|
let resultLocator = spotlight.results;
|
||||||
|
await expect(resultLocator).toHaveCount(1);
|
||||||
|
await expect(resultLocator.first()).toContainText(bot2Name);
|
||||||
|
await resultLocator.first().click();
|
||||||
|
|
||||||
|
// Send first message to actually start DM
|
||||||
|
await expect(roomHeaderName(page)).toHaveText(bot2Name);
|
||||||
|
const locator = page.getByRole("textbox", { name: "Send a message…" });
|
||||||
|
await locator.fill("Hey!");
|
||||||
|
await locator.press("Enter");
|
||||||
|
|
||||||
|
// Assert DM exists by checking for the first message and the room being in the room list
|
||||||
|
await expect(page.locator(".mx_EventTile_body").filter({ hasText: "Hey!" })).toBeAttached({ timeout: 3000 });
|
||||||
|
await expect(page.getByRole("group", { name: "People" })).toContainText(bot2Name);
|
||||||
|
|
||||||
|
// Invite BotBob into existing DM with ByteBot
|
||||||
|
const dmRooms = await app.client.evaluate((client, userId) => {
|
||||||
|
const map = client.getAccountData("m.direct")?.getContent<Record<string, string[]>>();
|
||||||
|
return map[userId] ?? [];
|
||||||
|
}, bot2UserId);
|
||||||
|
expect(dmRooms).toHaveLength(1);
|
||||||
|
const groupDmName = await app.client.evaluate((client, id) => client.getRoom(id).name, dmRooms[0]);
|
||||||
|
const bot1UserId = await bot1.evaluate((client) => client.getUserId());
|
||||||
|
await app.client.inviteUser(dmRooms[0], bot1UserId);
|
||||||
|
await expect(roomHeaderName(page).first()).toContainText(groupDmName);
|
||||||
|
await expect(page.getByRole("group", { name: "People" }).first()).toContainText(groupDmName);
|
||||||
|
|
||||||
|
// Search for BotBob by id, should return group DM and user
|
||||||
|
spotlight = await app.openSpotlight();
|
||||||
|
await spotlight.filter(Filter.People);
|
||||||
|
await spotlight.search(bot1UserId);
|
||||||
|
await page.waitForTimeout(1000); // wait for the dialog to settle
|
||||||
|
resultLocator = spotlight.results;
|
||||||
|
await expect(resultLocator).toHaveCount(2);
|
||||||
|
await expect(
|
||||||
|
spotlight.dialog
|
||||||
|
.locator(".mx_SpotlightDialog_section.mx_SpotlightDialog_results .mx_SpotlightDialog_option")
|
||||||
|
.filter({ hasText: groupDmName }),
|
||||||
|
).toBeAttached();
|
||||||
|
|
||||||
|
// Search for ByteBot by id, should return group DM and user
|
||||||
|
spotlight = await app.openSpotlight();
|
||||||
|
await spotlight.filter(Filter.People);
|
||||||
|
await spotlight.search(bot2UserId);
|
||||||
|
await page.waitForTimeout(1000); // wait for the dialog to settle
|
||||||
|
resultLocator = spotlight.results;
|
||||||
|
await expect(resultLocator).toHaveCount(2);
|
||||||
|
await expect(
|
||||||
|
spotlight.dialog
|
||||||
|
.locator(".mx_SpotlightDialog_section.mx_SpotlightDialog_results .mx_SpotlightDialog_option")
|
||||||
|
.filter({ hasText: groupDmName })
|
||||||
|
.last(),
|
||||||
|
).toBeAttached();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Test against https://github.com/vector-im/element-web/issues/22851
|
||||||
|
test("should show each person result only once", async ({ page, app }) => {
|
||||||
|
const spotlight = await app.openSpotlight();
|
||||||
|
await page.waitForTimeout(500); // wait for the dialog to settle
|
||||||
|
await spotlight.filter(Filter.People);
|
||||||
|
const bot1UserId = await bot1.evaluate((client) => client.getUserId());
|
||||||
|
|
||||||
|
// 2 rounds of search to simulate the bug conditions. Specifically, the first search
|
||||||
|
// should have 1 result (not 2) and the second search should also have 1 result (instead
|
||||||
|
// of the super buggy 3 described by https://github.com/vector-im/element-web/issues/22851)
|
||||||
|
//
|
||||||
|
// We search for user ID to trigger the profile lookup within the dialog.
|
||||||
|
for (let i = 0; i < 2; i++) {
|
||||||
|
console.log("Iteration: " + i);
|
||||||
|
await spotlight.search(bot1UserId);
|
||||||
|
await page.waitForTimeout(1000); // wait for the dialog to settle
|
||||||
|
const resultLocator = spotlight.results;
|
||||||
|
await expect(resultLocator).toHaveCount(1);
|
||||||
|
await expect(resultLocator.first()).toContainText(bot1UserId);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test("should allow opening group chat dialog", async ({ page, app }) => {
|
||||||
|
const spotlight = await app.openSpotlight();
|
||||||
|
await page.waitForTimeout(500); // wait for the dialog to settle
|
||||||
|
await spotlight.filter(Filter.People);
|
||||||
|
await spotlight.search(bot2Name);
|
||||||
|
await page.waitForTimeout(3000); // wait for the dialog to settle
|
||||||
|
|
||||||
|
const resultLocator = spotlight.results;
|
||||||
|
await expect(resultLocator).toHaveCount(1);
|
||||||
|
await expect(resultLocator.first()).toContainText(bot2Name);
|
||||||
|
|
||||||
|
await expect(spotlight.dialog.locator(".mx_SpotlightDialog_startGroupChat")).toContainText(
|
||||||
|
"Start a group chat",
|
||||||
|
);
|
||||||
|
await spotlight.dialog.locator(".mx_SpotlightDialog_startGroupChat").click();
|
||||||
|
await expect(page.getByRole("dialog")).toContainText("Direct Messages");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("should close spotlight after starting a DM", async ({ page, app }) => {
|
||||||
|
await startDM(app, page, bot1Name);
|
||||||
|
await expect(page.locator(".mx_SpotlightDialog")).toHaveCount(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("should show the same user only once", async ({ page, app }) => {
|
||||||
|
await startDM(app, page, bot1Name);
|
||||||
|
await page.goto("/#/home");
|
||||||
|
const spotlight = await app.openSpotlight();
|
||||||
|
await page.waitForTimeout(500); // wait for the dialog to settle
|
||||||
|
await spotlight.filter(Filter.People);
|
||||||
|
await spotlight.search(bot1Name);
|
||||||
|
await page.waitForTimeout(3000); // wait for the dialog to settle
|
||||||
|
await expect(spotlight.dialog.locator(".mx_Spinner")).not.toBeAttached();
|
||||||
|
const resultLocator = spotlight.results;
|
||||||
|
await expect(resultLocator).toHaveCount(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("should be able to navigate results via keyboard", async ({ page, app }) => {
|
||||||
|
const spotlight = await app.openSpotlight();
|
||||||
|
await page.waitForTimeout(500); // wait for the dialog to settle
|
||||||
|
await spotlight.filter(Filter.People);
|
||||||
|
await spotlight.search("b");
|
||||||
|
|
||||||
|
let resultLocator = spotlight.results;
|
||||||
|
await expect(resultLocator).toHaveCount(2);
|
||||||
|
await expect(resultLocator.first()).toHaveAttribute("aria-selected", "true");
|
||||||
|
await expect(resultLocator.last()).toHaveAttribute("aria-selected", "false");
|
||||||
|
|
||||||
|
await spotlight.searchBox.press("ArrowDown");
|
||||||
|
resultLocator = spotlight.results;
|
||||||
|
await expect(resultLocator.first()).toHaveAttribute("aria-selected", "false");
|
||||||
|
await expect(resultLocator.last()).toHaveAttribute("aria-selected", "true");
|
||||||
|
|
||||||
|
await spotlight.searchBox.press("ArrowDown");
|
||||||
|
resultLocator = spotlight.results;
|
||||||
|
await expect(resultLocator.first()).toHaveAttribute("aria-selected", "false");
|
||||||
|
await expect(resultLocator.last()).toHaveAttribute("aria-selected", "false");
|
||||||
|
|
||||||
|
await spotlight.searchBox.press("ArrowUp");
|
||||||
|
resultLocator = spotlight.results;
|
||||||
|
await expect(resultLocator.first()).toHaveAttribute("aria-selected", "false");
|
||||||
|
await expect(resultLocator.last()).toHaveAttribute("aria-selected", "true");
|
||||||
|
|
||||||
|
await spotlight.searchBox.press("ArrowUp");
|
||||||
|
resultLocator = spotlight.results;
|
||||||
|
await expect(resultLocator.first()).toHaveAttribute("aria-selected", "true");
|
||||||
|
await expect(resultLocator.last()).toHaveAttribute("aria-selected", "false");
|
||||||
|
});
|
||||||
|
});
|
|
@ -28,8 +28,13 @@ export class Spotlight {
|
||||||
constructor(private page: Page) {}
|
constructor(private page: Page) {}
|
||||||
|
|
||||||
public async open() {
|
public async open() {
|
||||||
await this.page.keyboard.press(`${CommandOrControl}+KeyK`);
|
|
||||||
this.root = this.page.locator('[role=dialog][aria-label="Search Dialog"]');
|
this.root = this.page.locator('[role=dialog][aria-label="Search Dialog"]');
|
||||||
|
const isSpotlightAlreadyOpen = !!(await this.root.count());
|
||||||
|
if (isSpotlightAlreadyOpen) {
|
||||||
|
// Close dialog if it is already open
|
||||||
|
await this.page.keyboard.press(`${CommandOrControl}+KeyK`);
|
||||||
|
}
|
||||||
|
await this.page.keyboard.press(`${CommandOrControl}+KeyK`);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async filter(filter: Filter) {
|
public async filter(filter: Filter) {
|
||||||
|
@ -49,10 +54,18 @@ export class Spotlight {
|
||||||
}
|
}
|
||||||
|
|
||||||
public async search(query: string) {
|
public async search(query: string) {
|
||||||
await this.root.locator(".mx_SpotlightDialog_searchBox").getByRole("textbox", { name: "Search" }).fill(query);
|
await this.searchBox.getByRole("textbox", { name: "Search" }).fill(query);
|
||||||
|
}
|
||||||
|
|
||||||
|
public get searchBox() {
|
||||||
|
return this.root.locator(".mx_SpotlightDialog_searchBox");
|
||||||
}
|
}
|
||||||
|
|
||||||
public get results() {
|
public get results() {
|
||||||
return this.root.locator(".mx_SpotlightDialog_section.mx_SpotlightDialog_results .mx_SpotlightDialog_option");
|
return this.root.locator(".mx_SpotlightDialog_section.mx_SpotlightDialog_results .mx_SpotlightDialog_option");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public get dialog() {
|
||||||
|
return this.root;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue