puppeteer_tests: Remove jQuery dependency.

Signed-off-by: Anders Kaseorg <anders@zulip.com>
This commit is contained in:
Anders Kaseorg 2021-03-26 20:40:48 -07:00 committed by Tim Abbott
parent 96f15e3665
commit dfda6d2895
14 changed files with 159 additions and 180 deletions

View File

@ -143,7 +143,6 @@
{
"files": ["frontend_tests/puppeteer_lib/**", "frontend_tests/puppeteer_tests/**"],
"globals": {
"$": false,
"zulip_test": false
}
},

View File

@ -106,6 +106,7 @@ export async function page_url_with_fragment(page: Page): Promise<string> {
export async function clear_and_type(page: Page, selector: string, text: string): Promise<void> {
// Select all text currently in the element.
await page.click(selector, {clickCount: 3});
await page.keyboard.press("Delete");
await page.type(selector, text);
}
@ -301,6 +302,10 @@ export async function assert_compose_box_content(
}
export async function wait_for_fully_processed_message(page: Page, content: string): Promise<void> {
// Wait in parallel for the message list scroll animation, which
// interferes with Puppeteer accurately clicking on messages.
const scroll_delay = page.waitForTimeout(400);
await page.waitForFunction(
(content: string) => {
/*
@ -354,6 +359,8 @@ export async function wait_for_fully_processed_message(page: Page, content: stri
{},
content,
);
await scroll_delay;
}
// Wait for any previous send to finish, then send a message.

View File

@ -35,17 +35,11 @@ async function test_change_new_stream_notifications_setting(page: Page): Promise
"#realm_notifications_stream_id_widget .dropdown-search > input[type=text]",
"rome",
);
await page.waitForFunction(
() =>
$(
"#realm_notifications_stream_id_widget .dropdown-search > input[type=text]",
).val() === "rome",
);
const rome_in_dropdown = await page.waitForSelector(
`xpath///*[@id="realm_notifications_stream_id_widget"]//*[${common.has_class_x(
"dropdown-list-body",
)}]/li[1]`,
)} and count(li)=1]/li[normalize-space()="Rome"]`,
{visible: true},
);
assert.ok(rome_in_dropdown);
@ -126,11 +120,7 @@ async function test_changing_create_streams_and_invite_to_stream_policies(
for (const [policy_value_name, policy_value] of Object.entries(policy_values)) {
console.log(`Test setting ${policy} policy to '${policy_value_name}'.`);
await page.waitForSelector(selector, {visible: true});
await page.evaluate(
(selector, policy_value) => $(selector).val(policy_value).trigger("change"),
selector,
policy_value,
);
await page.select(selector, `${policy_value}`);
await submit_stream_permissions_change(page);
}
}
@ -161,21 +151,17 @@ async function submit_joining_organization_change(page: Page): Promise<void> {
async function test_set_new_user_threshold_to_three_days(page: Page): Promise<void> {
console.log("Test setting new user threshold to three days.");
await page.waitForSelector("#id_realm_waiting_period_setting", {visible: true});
await page.evaluate(() =>
$("#id_realm_waiting_period_setting").val("three_days").trigger("change"),
);
await page.select("#id_realm_waiting_period_setting", "three_days");
await submit_joining_organization_change(page);
}
async function test_set_new_user_threshold_to_N_days(page: Page): Promise<void> {
console.log("Test setting new user threshold to three days.");
await page.waitForSelector("#id_realm_waiting_period_setting", {visible: true});
await page.evaluate(() =>
$("#id_realm_waiting_period_setting").val("custom_days").trigger("change"),
);
await page.select("#id_realm_waiting_period_setting", "custom_days");
const N = 10;
await page.evaluate((N: number) => $("#id_realm_waiting_period_threshold").val(N), N);
const N = "10";
await common.clear_and_type(page, "#id_realm_waiting_period_threshold", N);
await submit_joining_organization_change(page);
}
@ -218,7 +204,7 @@ async function test_delete_emoji(page: Page): Promise<void> {
await page.click("tr#emoji_zulip_logo button.delete");
// assert the emoji is deleted.
await page.waitForFunction(() => $("tr#emoji_zulip_logo").length === 0);
await page.waitForSelector("tr#emoji_zulip_logo", {hidden: true});
}
async function test_custom_realm_emoji(page: Page): Promise<void> {
@ -229,28 +215,6 @@ async function test_custom_realm_emoji(page: Page): Promise<void> {
await test_delete_emoji(page);
}
async function get_suggestions(page: Page, str: string): Promise<void> {
await page.evaluate((str: string) => {
$(".create_default_stream")
.trigger("focus")
.val(str)
.trigger(new $.Event("keyup", {which: 0}));
}, str);
}
async function select_from_suggestions(page: Page, item: string): Promise<void> {
await page.evaluate((item: string) => {
const tah = $(".create_default_stream").data().typeahead;
tah.mousemove({
currentTarget: $(`.typeahead:visible li:contains("${CSS.escape(item)}")`)[0],
});
tah.mouseenter({
currentTarget: $(`.typeahead:visible li:contains("${CSS.escape(item)}")`)[0],
});
tah.select();
}, item);
}
async function test_add_default_stream(
page: Page,
stream_name: string,
@ -260,8 +224,7 @@ async function test_add_default_stream(
// etc). 'O' is used to make sure that it works even if there are multiple suggestions.
// Uppercase 'O' is used instead of the lowercase version to make sure that the suggestions
// are case insensitive.
await get_suggestions(page, "o");
await select_from_suggestions(page, stream_name);
await common.select_item_via_typeahead(page, ".create_default_stream", "O", stream_name);
await page.click(".default-stream-form #do_submit_stream");
await page.waitForSelector(row, {visible: true});
@ -271,7 +234,7 @@ async function test_remove_default_stream(page: Page, row: string): Promise<void
await page.click(row + " button.remove-default-stream");
// assert row doesn't exist.
await page.waitForFunction((row: string) => $(row).length === 0, {}, row);
await page.waitForSelector(row, {hidden: true});
}
async function test_default_streams(page: Page): Promise<void> {
@ -349,10 +312,8 @@ async function test_authentication_methods(page: Page): Promise<void> {
await page.waitForSelector(".method_row[data-method='Google'] input[type='checkbox'] + span", {
visible: true,
});
await page.waitForFunction(
() =>
!($(".method_row[data-method='Google'] input[type='checkbox']")[0] as HTMLInputElement)
.checked,
await page.waitForSelector(
".method_row[data-method='Google'] input[type='checkbox']:not(:checked)",
);
}

View File

@ -22,17 +22,14 @@ function get_message_selector(text: string): string {
}
async function test_send_messages(page: Page): Promise<void> {
const initial_msgs_count = await page.evaluate(() => $("#zhome .message_row").length);
const initial_msgs_count = (await page.$$("#zhome .message_row")).length;
await common.send_multiple_messages(page, [
{stream: "Verona", topic: "Reply test", content: "Compose stream reply test"},
{recipient: "cordelia@zulip.com", content: "Compose private message reply test"},
]);
assert.equal(
await page.evaluate(() => $("#zhome .message_row").length),
initial_msgs_count + 2,
);
assert.equal((await page.$$("#zhome .message_row")).length, initial_msgs_count + 2);
}
async function test_stream_compose_keyboard_shortcut(page: Page): Promise<void> {
@ -120,16 +117,15 @@ async function test_narrow_to_private_messages_with_cordelia(page: Page): Promis
await page.keyboard.press("KeyC");
await page.waitForSelector("#compose", {visible: true});
await page.waitForFunction(
() => document.activeElement === $(".compose_table #stream_message_recipient_stream")[0],
);
await page.waitForSelector(".compose_table #stream_message_recipient_stream:focus", {
visible: true,
});
await close_compose_box(page);
}
async function test_send_multirecipient_pm_from_cordelia_pm_narrow(page: Page): Promise<void> {
const recipients = ["cordelia@zulip.com", "othello@zulip.com"];
const multiple_recipients_pm = "A huddle to check spaces";
const pm_selector = `.messagebox:contains('${CSS.escape(multiple_recipients_pm)}')`;
await common.send_message(page, "private", {
recipient: recipients.join(", "),
outside_view: true,
@ -140,10 +136,13 @@ async function test_send_multirecipient_pm_from_cordelia_pm_narrow(page: Page):
await page.click(".top_left_all_messages");
await page.waitForSelector("#zhome .message_row", {visible: true});
await page.waitForFunction((selector: string) => $(selector).length !== 0, {}, pm_selector);
await page.evaluate((selector: string) => {
$(selector).slice(-1)[0].click();
}, pm_selector);
const pm = await page.waitForSelector(
`xpath/(//*[${common.has_class_x(
"messagebox",
)} and contains(normalize-space(), "${multiple_recipients_pm}")])[last()]`,
);
assert.ok(pm !== null);
await pm.click();
await page.waitForSelector("#compose-textarea", {visible: true});
const recipient_internal_emails = [
await common.get_internal_email_from_name(page, "othello"),
@ -184,24 +183,21 @@ async function test_markdown_preview_without_any_content(page: Page): Promise<vo
async function test_markdown_rendering(page: Page): Promise<void> {
await page.waitForSelector("#compose .markdown_preview", {visible: true});
let markdown_preview_element = await page.$("#compose .preview_content");
assert.ok(markdown_preview_element);
assert.equal(
await page.evaluate((element: Element) => element.textContent, markdown_preview_element),
"",
);
assert.equal(await common.get_text_from_selector(page, "#compose .preview_content"), "");
await common.fill_form(page, 'form[action^="/json/messages"]', {
content: "**Markdown preview** >> Test for Markdown preview",
});
await page.click("#compose .markdown_preview");
await page.waitForSelector("#compose .preview_content", {visible: true});
const preview_content = (await page.waitForSelector(
`xpath///*[@id="compose"]//*[${common.has_class_x(
"preview_content",
)} and normalize-space()!=""]`,
{visible: true},
)) as ElementHandle<Element>;
const expected_markdown_html =
"<p><strong>Markdown preview</strong> &gt;&gt; Test for Markdown preview</p>";
await page.waitForFunction(() => $("#compose .preview_content").html() !== "");
markdown_preview_element = await page.$("#compose .preview_content");
assert.ok(markdown_preview_element);
assert.equal(
await page.evaluate((element: Element) => element.innerHTML, markdown_preview_element),
await (await preview_content.getProperty("innerHTML")).jsonValue(),
expected_markdown_html,
);
}

View File

@ -12,7 +12,9 @@ async function copy_messages(
return await page.evaluate(
(start_message: string, end_message: string) => {
function get_message_node(message: string): Element {
return $(`.message_row .message_content:contains("${CSS.escape(message)}")`)[0];
return [...document.querySelectorAll("#zhome .message_content")].find(
(node) => node.textContent?.trim() === message,
)!;
}
// select messages from start_message to end_message
@ -25,17 +27,21 @@ async function copy_messages(
// Remove existing copy/paste divs, which may linger from the previous
// example. (The code clears these out with a zero-second timeout, which
// is probably sufficient for human users, but which causes problems here.)
$("#copytempdiv").remove();
document.querySelector("#copytempdiv")?.remove();
// emulate copy event
$("body").trigger(new $.Event("keydown", {which: 67, ctrlKey: true}));
document.dispatchEvent(
new KeyboardEvent("keydown", {
key: "c",
code: "KeyC",
ctrlKey: true,
keyCode: 67,
which: 67,
} as KeyboardEventInit),
);
// find temp div with copied text
const $temp_div = $("#copytempdiv");
return $temp_div
.children("p")
.get()
.map((p) => p.textContent!);
return [...document.querySelectorAll("#copytempdiv > p")].map((p) => p.textContent!);
},
start_message,
end_message,

View File

@ -1,21 +1,29 @@
import type {Page} from "puppeteer";
import {strict as assert} from "assert";
import type {ElementHandle, Page} from "puppeteer";
import * as common from "../puppeteer_lib/common";
async function click_delete_and_return_last_msg_id(page: Page): Promise<string | undefined> {
return await page.evaluate(() => {
const $msg = $("#zhome .message_row").last();
$msg.find(".message_control_button.actions_hover").trigger("click");
$(".delete_message").trigger("click");
return $msg.attr("id");
});
async function click_delete_and_return_last_msg_id(page: Page): Promise<string> {
const msg = (await page.$$("#zhome .message_row")).at(-1) as ElementHandle<Element>;
const id = await (await msg.getProperty("id")).jsonValue();
await msg.hover();
const info = await page.waitForSelector(
`#${CSS.escape(id)} .message_control_button.actions_hover`,
{visible: true},
);
assert.ok(info !== null);
await info.click();
await page.waitForSelector(".delete_message", {visible: true});
await page.click(".delete_message");
return id;
}
async function delete_message_test(page: Page): Promise<void> {
await common.log_in(page);
await page.click(".top_left_all_messages");
await page.waitForSelector("#zhome .message_row", {visible: true});
const messages_quantitiy = await page.evaluate(() => $("#zhome .message_row").length);
const messages_quantity = (await page.$$("#zhome .message_row")).length;
const last_message_id = await click_delete_and_return_last_msg_id(page);
await common.wait_for_micromodal_to_open(page);
@ -24,13 +32,8 @@ async function delete_message_test(page: Page): Promise<void> {
});
await common.wait_for_micromodal_to_close(page);
await page.waitForFunction(
(expected_length: number) => $("#zhome .message_row").length === expected_length,
{},
messages_quantitiy - 1,
);
await page.waitForSelector(`#${CSS.escape(last_message_id!)}`, {hidden: true});
await page.waitForSelector(`#${CSS.escape(last_message_id)}`, {hidden: true});
assert.equal((await page.$$("#zhome .message_row")).length, messages_quantity - 1);
}
common.run_test(delete_message_test);

View File

@ -5,15 +5,11 @@ import type {Page} from "puppeteer";
import * as common from "../puppeteer_lib/common";
async function wait_for_drafts_to_disappear(page: Page): Promise<void> {
await page.waitForFunction(
() => $("#draft_overlay").length === 0 || $("#draft_overlay").css("opacity") === "0",
);
await page.waitForSelector("#draft_overlay.show", {hidden: true});
}
async function wait_for_drafts_to_appear(page: Page): Promise<void> {
await page.waitForFunction(
() => $("#draft_overlay").length === 1 && $("#draft_overlay").css("opacity") === "1",
);
await page.waitForSelector("#draft_overlay.show");
}
async function get_drafts_count(page: Page): Promise<number> {

View File

@ -1,13 +1,21 @@
import type {Page} from "puppeteer";
import {strict as assert} from "assert";
import type {ElementHandle, Page} from "puppeteer";
import * as common from "../puppeteer_lib/common";
async function trigger_edit_last_message(page: Page): Promise<void> {
await page.evaluate(() => {
const $msg = $("#zhome .message_row").last();
$msg.find(".message_control_button.actions_hover").trigger("click");
$(".popover_edit_message").trigger("click");
});
const msg = (await page.$$("#zhome .message_row")).at(-1) as ElementHandle<Element>;
const id = await (await msg.getProperty("id")).jsonValue();
await msg.hover();
const info = await page.waitForSelector(
`#${CSS.escape(id)} .message_control_button.actions_hover`,
{visible: true},
);
assert.ok(info !== null);
await info.click();
await page.waitForSelector(".popover_edit_message", {visible: true});
await page.click(".popover_edit_message");
await page.waitForSelector(".message_edit_content", {visible: true});
}
@ -34,25 +42,35 @@ async function test_stream_message_edit(page: Page): Promise<void> {
}
async function test_edit_message_with_slash_me(page: Page): Promise<void> {
const last_message_xpath = `(//*[@id="zhome"]//*[${common.has_class_x("messagebox")}])[last()]`;
await common.send_message(page, "stream", {
stream: "Verona",
topic: "edits",
content: "/me test editing a message with me",
});
await page.waitForFunction(
() => $(".last_message .status-message").text() === "test editing a message with me",
await page.waitForSelector(
`xpath/${last_message_xpath}//*[${common.has_class_x(
"status-message",
)} and text()="test editing a message with me"]`,
);
await page.waitForFunction(
() => $(".last_message .sender_name-in-status").text().trim() === "Desdemona",
await page.waitForSelector(
`xpath/${last_message_xpath}//*[${common.has_class_x(
"sender_name-in-status",
)} and normalize-space()="Desdemona"]`,
);
await edit_stream_message(page, "edited", "/me test edited a message with me");
await page.waitForFunction(
() => $(".last_message .status-message").text() === "test edited a message with me",
await page.waitForSelector(
`xpath/${last_message_xpath}//*[${common.has_class_x(
"status-message",
)} and text()="test edited a message with me"]`,
);
await page.waitForFunction(
() => $(".last_message .sender_name-in-status").text().trim() === "Desdemona",
await page.waitForSelector(
`xpath/${last_message_xpath}//*[${common.has_class_x(
"sender_name-in-status",
)} and normalize-space()="Desdemona"]`,
);
}

View File

@ -81,7 +81,7 @@ async function expect_cordelia_private_narrow(page: Page): Promise<void> {
}
async function un_narrow(page: Page): Promise<void> {
if (await page.evaluate(() => $(".message_comp").is(":visible"))) {
if ((await (await page.$(".message_comp"))!.boundingBox())?.height) {
await page.keyboard.press("Escape");
}
await page.click(".top_left_all_messages");
@ -100,7 +100,7 @@ async function expect_recent_topics(page: Page): Promise<void> {
async function test_navigations_from_home(page: Page): Promise<void> {
console.log("Narrowing by clicking stream");
await page.evaluate(() => $(`*[title='Narrow to stream "Verona"']`).trigger("click"));
await page.click(`#zhome [title='Narrow to stream "Verona"']`);
await expect_verona_stream(page);
assert.strictEqual(await page.title(), "Verona - Zulip Dev - Zulip");
@ -108,27 +108,23 @@ async function test_navigations_from_home(page: Page): Promise<void> {
await expect_home(page);
console.log("Narrowing by clicking topic");
await page.click('*[title="Narrow to stream \\"Verona\\", topic \\"test\\""]');
await page.click(`#zhome [title='Narrow to stream "Verona", topic "test"']`);
await expect_verona_stream_test_topic(page);
await un_narrow(page);
await expect_home(page);
console.log("Narrowing by clicking group personal header");
await page.evaluate(() =>
$(
'*[title="Narrow to your private messages with Cordelia, Lear\'s daughter, King Hamlet"]',
).trigger("click"),
await page.click(
`#zhome [title="Narrow to your private messages with Cordelia, Lear's daughter, King Hamlet"]`,
);
await expect_huddle(page);
await un_narrow(page);
await expect_home(page);
await page.evaluate(() =>
$(
'*[title="Narrow to your private messages with Cordelia, Lear\'s daughter, King Hamlet"]',
).trigger("click"),
await page.click(
`#zhome [title="Narrow to your private messages with Cordelia, Lear's daughter, King Hamlet"]`,
);
await un_narrow_by_clicking_org_icon(page);
await expect_recent_topics(page);
@ -294,15 +290,7 @@ async function arrow(page: Page, direction: "Up" | "Down"): Promise<void> {
}
async function test_search_venice(page: Page): Promise<void> {
await page.evaluate(() => {
$(".stream-list-filter")
.expectOne()
.trigger("focus")
.val("vEnI") // Must be case insensitive.
.trigger("input")
.trigger("click");
});
await common.clear_and_type(page, ".stream-list-filter", "vEnI"); // Must be case insensitive.
await page.waitForSelector(await get_stream_li(page, "Denmark"), {hidden: true});
await page.waitForSelector(await get_stream_li(page, "Verona"), {hidden: true});
await page.waitForSelector((await get_stream_li(page, "Venice")) + ".highlighted_stream", {
@ -310,9 +298,7 @@ async function test_search_venice(page: Page): Promise<void> {
});
// Clearing list gives back all the streams in the list
await page.evaluate(() =>
$(".stream-list-filter").expectOne().trigger("focus").val("").trigger("input"),
);
await common.clear_and_type(page, ".stream-list-filter", "");
await page.waitForSelector(await get_stream_li(page, "Denmark"), {visible: true});
await page.waitForSelector(await get_stream_li(page, "Venice"), {visible: true});
await page.waitForSelector(await get_stream_li(page, "Verona"), {visible: true});
@ -463,17 +449,20 @@ async function test_narrow_public_streams(page: Page): Promise<void> {
await page.goto(`http://zulip.zulipdev.com:9981/#streams/${stream_id}/Denmark`);
await page.waitForSelector("button.sub_unsub_button", {visible: true});
await page.click("button.sub_unsub_button");
await page.waitForFunction(() => $("button.sub_unsub_button").text().trim() === "Subscribe");
await page.waitForSelector(
`xpath///button[${common.has_class_x(
"sub_unsub_button",
)} and normalize-space()="Subscribe"]`,
);
await page.click(".subscriptions-header .exit-sign");
await page.waitForSelector("#subscription_overlay", {hidden: true});
await page.goto(`http://zulip.zulipdev.com:9981/#narrow/stream/${stream_id}-Denmark`);
await page.waitForFunction(() => $(".recipient_row:visible").length >= 3);
assert.equal(await page.evaluate(() => $(".stream-status:visible").length), 1);
await page.waitForSelector("#zfilt .recipient_row ~ .recipient_row ~ .recipient_row");
assert.ok((await page.$("#zfilt .stream-status")) !== null);
await page.goto("http://zulip.zulipdev.com:9981/#narrow/streams/public");
await page.waitForFunction(() => $(".recipient_row:visible").length >= 3);
assert.equal(await page.evaluate(() => $(".stream-status:visible").length), 0);
await page.waitForSelector("#zfilt .recipient_row ~ .recipient_row ~ .recipient_row");
assert.ok((await page.$("#zfilt .stream-status")) === null);
}
async function message_basic_tests(page: Page): Promise<void> {

View File

@ -93,9 +93,7 @@ async function navigation_tests(page: Page): Promise<void> {
await navigate_using_left_sidebar(page, verona_narrow, "message_feed_container");
// Hardcoded this instead of using `navigate_to`
// as Puppeteer cannot click hidden elements.
await page.evaluate(() => $("a[href='#message_feed_container]'").trigger("click"));
await page.click(".home-link");
await wait_for_tab(page, "message_feed_container");
await navigate_to_subscriptions(page);

View File

@ -1,6 +1,6 @@
import {strict as assert} from "assert";
import type {Page} from "puppeteer";
import type {ElementHandle, Page} from "puppeteer";
import {test_credentials} from "../../var/puppeteer/test_credentials";
import * as common from "../puppeteer_lib/common";
@ -12,10 +12,8 @@ const zuliprc_regex =
/^data:application\/octet-stream;charset=utf-8,\[api]\nemail=.+\nkey=.+\nsite=.+\n$/;
async function get_decoded_url_in_selector(page: Page, selector: string): Promise<string> {
return await page.evaluate(
(selector: string) => decodeURIComponent($(selector).attr("href")!),
selector,
);
const a = (await page.$(selector)) as ElementHandle<HTMLAnchorElement>;
return decodeURIComponent(await (await a.getProperty("href")).jsonValue());
}
async function open_settings(page: Page): Promise<void> {
@ -43,7 +41,9 @@ async function test_change_full_name(page: Page): Promise<void> {
await page.click("#settings_content .profile-settings-form");
await page.waitForSelector(".full-name-change-form .alert-success", {visible: true});
await page.waitForFunction(() => $("#full_name").val() === "New name");
await page.waitForFunction(
() => document.querySelector<HTMLInputElement>("#full_name")?.value === "New name",
);
}
async function test_change_password(page: Page): Promise<void> {

View File

@ -7,23 +7,24 @@ import * as common from "../puppeteer_lib/common";
const message = "test star";
async function stars_count(page: Page): Promise<number> {
return await page.evaluate(() => $("#zhome .fa-star:not(.empty-star)").length);
return (await page.$$("#zhome .fa-star:not(.empty-star)")).length;
}
async function toggle_test_star_message(page: Page): Promise<void> {
await page.evaluate((message: string) => {
const $msg = $(`.message_content:contains("${CSS.escape(message)}"):visible`).last();
if ($msg.length !== 1) {
throw new Error("cannot find test star message");
}
const messagebox = await page.waitForSelector(
`xpath/(//*[@id="zhome"]//*[${common.has_class_x(
"message_content",
)} and normalize-space()="${message}"])[last()]/ancestor::*[${common.has_class_x(
"messagebox",
)}]`,
{visible: true},
);
assert.ok(messagebox !== null);
await messagebox.hover();
const $star_icon = $msg.closest(".messagebox").find(".star");
if ($star_icon.length !== 1) {
throw new Error("cannot find star icon");
}
$star_icon.trigger("click");
}, message);
const star_icon = await messagebox.waitForSelector(".star", {visible: true});
assert.ok(star_icon !== null);
await star_icon.click();
}
async function test_narrow_to_starred_messages(page: Page): Promise<void> {

View File

@ -84,7 +84,9 @@ async function create_stream(page: Page): Promise<void> {
stream_description: "Everything Puppeteer",
});
await page.click("form#stream_creation_form .finalize_create_stream");
await page.waitForFunction(() => $(".stream-name").is(':contains("Puppeteer")'));
await page.waitForSelector(
`xpath///*[${common.has_class_x("stream-name")} and text()="Puppeteer"]`,
);
const stream_name = await common.get_text_from_selector(
page,
".stream-header .stream-name .sub-stream-name",
@ -93,15 +95,14 @@ async function create_stream(page: Page): Promise<void> {
page,
".stream-description .sub-stream-description",
);
const subscriber_count_selector = "[data-stream-name='Puppeteer'] .subscriber-count";
assert.strictEqual(stream_name, "Puppeteer");
assert.strictEqual(stream_description, "Everything Puppeteer");
// Assert subscriber count becomes 3 (cordelia, desdemona, othello)
await page.waitForFunction(
(subscriber_count_selector: string) => $(subscriber_count_selector).text().trim() === "3",
{},
subscriber_count_selector,
await page.waitForSelector(
`xpath///*[@data-stream-name="Puppeteer"]//*[${common.has_class_x(
"subscriber-count",
)} and normalize-space()="3"]`,
);
}

View File

@ -9,15 +9,19 @@ async function test_subscription_button(page: Page): Promise<void> {
const unsubscribed_selector = `${button_selector}:not(.checked)`;
async function subscribed(): Promise<ElementHandle | null> {
await page.waitForFunction(
() => $(".stream_settings_header .sub_unsub_button").text().trim() === "Unsubscribe",
await page.waitForSelector(
`xpath///*[${common.has_class_x("stream_settings_header")}]//*[${common.has_class_x(
"sub_unsub_button",
)} and normalize-space()="Unsubscribe"]`,
);
return await page.waitForSelector(subscribed_selector, {visible: true});
}
async function unsubscribed(): Promise<ElementHandle | null> {
await page.waitForFunction(
() => $(".stream_settings_header .sub_unsub_button").text().trim() === "Subscribe",
await page.waitForSelector(
`xpath///*[${common.has_class_x("stream_settings_header")}]//*[${common.has_class_x(
"sub_unsub_button",
)} and normalize-space()="Subscribe"]`,
);
return await page.waitForSelector(unsubscribed_selector, {visible: true});
}