mirror of https://github.com/zulip/zulip.git
puppeteer_tests: Port to TypeScript.
Signed-off-by: Anders Kaseorg <anders@zulip.com>
This commit is contained in:
parent
cdff4cfe53
commit
279c4b0e24
|
@ -6,5 +6,8 @@
|
|||
/static/generated
|
||||
/static/third
|
||||
/static/webpack-bundles
|
||||
/var
|
||||
/var/*
|
||||
!/var/puppeteer
|
||||
/var/puppeteer/*
|
||||
!/var/puppeteer/test_credentials.d.ts
|
||||
/zulip-py3-venv
|
||||
|
|
|
@ -27,7 +27,10 @@
|
|||
package-lock.json
|
||||
|
||||
/.vagrant
|
||||
/var
|
||||
/var/*
|
||||
!/var/puppeteer
|
||||
/var/puppeteer/*
|
||||
!/var/puppeteer/test_credentials.d.ts
|
||||
|
||||
/.dmypy.json
|
||||
|
||||
|
|
|
@ -1,22 +1,22 @@
|
|||
"use strict";
|
||||
import {strict as assert} from "assert";
|
||||
import "css.escape";
|
||||
import path from "path";
|
||||
|
||||
const {strict: assert} = require("assert");
|
||||
const path = require("path");
|
||||
import {Browser, Page, launch} from "puppeteer";
|
||||
|
||||
require("css.escape");
|
||||
const puppeteer = require("puppeteer");
|
||||
|
||||
const {test_credentials} = require("../../var/puppeteer/test_credentials");
|
||||
import {test_credentials} from "../../var/puppeteer/test_credentials";
|
||||
|
||||
const root_dir = path.resolve(__dirname, "../../");
|
||||
const puppeteer_dir = path.join(root_dir, "var/puppeteer");
|
||||
|
||||
type Message = Record<string, string | boolean> & {recipient?: string; content: string};
|
||||
|
||||
class CommonUtils {
|
||||
browser = null;
|
||||
browser: Browser | null = null;
|
||||
screenshot_id = 0;
|
||||
realm_url = "http://zulip.zulipdev.com:9981/";
|
||||
pm_recipient = {
|
||||
async set(page, recipient) {
|
||||
async set(page: Page, recipient: string): Promise<void> {
|
||||
// Without using the delay option here there seems to be
|
||||
// a flake where the typeahead doesn't show up.
|
||||
await page.type("#private_message_recipient", recipient, {delay: 100});
|
||||
|
@ -37,7 +37,7 @@ class CommonUtils {
|
|||
});
|
||||
},
|
||||
|
||||
async expect(page, expected) {
|
||||
async expect(page: Page, expected: string): Promise<void> {
|
||||
const actual_recipients = await page.evaluate(() => {
|
||||
const compose_state = window.require("./static/js/compose_state");
|
||||
return compose_state.private_message_recipient();
|
||||
|
@ -46,7 +46,7 @@ class CommonUtils {
|
|||
},
|
||||
};
|
||||
|
||||
fullname = {
|
||||
fullname: Record<string, string> = {
|
||||
cordelia: "Cordelia Lear",
|
||||
othello: "Othello, the Moor of Venice",
|
||||
hamlet: "King Hamlet",
|
||||
|
@ -57,10 +57,10 @@ class CommonUtils {
|
|||
height: 1024,
|
||||
};
|
||||
|
||||
async ensure_browser() {
|
||||
async ensure_browser(): Promise<Browser> {
|
||||
if (this.browser === null) {
|
||||
const {window_size} = this;
|
||||
this.browser = await puppeteer.launch({
|
||||
this.browser = await launch({
|
||||
args: [
|
||||
`--window-size=${window_size.width},${window_size.height}`,
|
||||
"--no-sandbox",
|
||||
|
@ -70,15 +70,16 @@ class CommonUtils {
|
|||
headless: true,
|
||||
});
|
||||
}
|
||||
return this.browser;
|
||||
}
|
||||
|
||||
async get_page() {
|
||||
await this.ensure_browser();
|
||||
const page = await this.browser.newPage();
|
||||
async get_page(): Promise<Page> {
|
||||
const browser = await this.ensure_browser();
|
||||
const page = await browser.newPage();
|
||||
return page;
|
||||
}
|
||||
|
||||
async screenshot(page, name = null) {
|
||||
async screenshot(page: Page, name: string | null = null): Promise<void> {
|
||||
if (name === null) {
|
||||
name = `${this.screenshot_id}`;
|
||||
this.screenshot_id += 1;
|
||||
|
@ -107,8 +108,12 @@ class CommonUtils {
|
|||
* terms: true
|
||||
* });
|
||||
*/
|
||||
async fill_form(page, form_selector, params) {
|
||||
async function is_dropdown(page, name) {
|
||||
async fill_form(
|
||||
page: Page,
|
||||
form_selector: string,
|
||||
params: Record<string, boolean | string>,
|
||||
): Promise<void> {
|
||||
async function is_dropdown(page: Page, name: string): Promise<boolean> {
|
||||
return (await page.$(`select[name="${name}"]`)) !== null;
|
||||
}
|
||||
for (const name of Object.keys(params)) {
|
||||
|
@ -118,37 +123,44 @@ class CommonUtils {
|
|||
await page.$eval(
|
||||
name_selector,
|
||||
(el, value) => {
|
||||
if (el.checked !== value) {
|
||||
if (el instanceof HTMLInputElement && el.checked !== value) {
|
||||
el.click();
|
||||
}
|
||||
},
|
||||
value,
|
||||
);
|
||||
} else if (await is_dropdown(page, name)) {
|
||||
await page.select(name_selector, params[name]);
|
||||
if (typeof value !== "string") {
|
||||
throw new TypeError(`Expected string for ${name}`);
|
||||
}
|
||||
await page.select(name_selector, value);
|
||||
} else {
|
||||
// clear any existing text in the input field before filling.
|
||||
await page.$eval(name_selector, (el) => {
|
||||
el.value = "";
|
||||
(el as HTMLInputElement).value = "";
|
||||
});
|
||||
await page.type(name_selector, params[name]);
|
||||
await page.type(name_selector, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async check_form_contents(page, form_selector, params) {
|
||||
async check_form_contents(
|
||||
page: Page,
|
||||
form_selector: string,
|
||||
params: Record<string, boolean | string>,
|
||||
): Promise<void> {
|
||||
for (const name of Object.keys(params)) {
|
||||
const name_selector = `${form_selector} [name="${name}"]`;
|
||||
const expected_value = params[name];
|
||||
if (typeof expected_value === "boolean") {
|
||||
assert.equal(
|
||||
await page.$eval(name_selector, (el) => el.checked),
|
||||
await page.$eval(name_selector, (el) => (el as HTMLInputElement).checked),
|
||||
expected_value,
|
||||
"Form content is not as expected.",
|
||||
);
|
||||
} else {
|
||||
assert.equal(
|
||||
await page.$eval(name_selector, (el) => el.value),
|
||||
await page.$eval(name_selector, (el) => (el as HTMLInputElement).value),
|
||||
expected_value,
|
||||
"Form content is not as expected.",
|
||||
);
|
||||
|
@ -156,48 +168,51 @@ class CommonUtils {
|
|||
}
|
||||
}
|
||||
|
||||
async get_text_from_selector(page, selector) {
|
||||
return await page.evaluate((selector) => $(selector).text().trim(), selector);
|
||||
async get_text_from_selector(page: Page, selector: string): Promise<string> {
|
||||
return await page.evaluate((selector: string) => $(selector).text().trim(), selector);
|
||||
}
|
||||
|
||||
async wait_for_text(page, selector, text) {
|
||||
async wait_for_text(page: Page, selector: string, text: string): Promise<void> {
|
||||
await page.waitForFunction(
|
||||
(selector, text) => $(selector).text().includes(text),
|
||||
(selector: string, text: string) => $(selector).text().includes(text),
|
||||
{},
|
||||
selector,
|
||||
text,
|
||||
);
|
||||
}
|
||||
|
||||
async get_stream_id(page, stream_name) {
|
||||
return await page.evaluate((stream_name) => {
|
||||
async get_stream_id(page: Page, stream_name: string): Promise<number> {
|
||||
return await page.evaluate((stream_name: string) => {
|
||||
const stream_data = window.require("./static/js/stream_data");
|
||||
return stream_data.get_stream_id(stream_name);
|
||||
}, stream_name);
|
||||
}
|
||||
|
||||
async get_user_id_from_name(page, name) {
|
||||
async get_user_id_from_name(page: Page, name: string): Promise<number> {
|
||||
if (this.fullname[name] !== undefined) {
|
||||
name = this.fullname[name];
|
||||
}
|
||||
return await page.evaluate((name) => {
|
||||
const people = require("./static/js/people");
|
||||
return await page.evaluate((name: string) => {
|
||||
const people = window.require("./static/js/people");
|
||||
return people.get_user_id_from_name(name);
|
||||
}, name);
|
||||
}
|
||||
|
||||
async get_internal_email_from_name(page, name) {
|
||||
async get_internal_email_from_name(page: Page, name: string): Promise<string> {
|
||||
if (this.fullname[name] !== undefined) {
|
||||
name = this.fullname[name];
|
||||
}
|
||||
return await page.evaluate((fullname) => {
|
||||
const people = require("./static/js/people");
|
||||
return await page.evaluate((fullname: string) => {
|
||||
const people = window.require("./static/js/people");
|
||||
const user_id = people.get_user_id_from_name(fullname);
|
||||
return people.get_by_user_id(user_id).email;
|
||||
}, name);
|
||||
}
|
||||
|
||||
async log_in(page, credentials = null) {
|
||||
async log_in(
|
||||
page: Page,
|
||||
credentials: {username: string; password: string} | null = null,
|
||||
): Promise<void> {
|
||||
console.log("Logging in");
|
||||
await page.goto(this.realm_url + "login/");
|
||||
assert.equal(this.realm_url + "login/", page.url());
|
||||
|
@ -210,12 +225,12 @@ class CommonUtils {
|
|||
password: credentials.password,
|
||||
};
|
||||
await this.fill_form(page, "#login_form", params);
|
||||
await page.$eval("#login_form", (form) => form.submit());
|
||||
await page.$eval("#login_form", (form) => (form as HTMLFormElement).submit());
|
||||
|
||||
await page.waitForSelector("#zhome .message_row", {visible: true});
|
||||
}
|
||||
|
||||
async log_out(page) {
|
||||
async log_out(page: Page): Promise<void> {
|
||||
await page.goto(this.realm_url);
|
||||
const menu_selector = "#settings-dropdown";
|
||||
const logout_selector = 'a[href="#logout"]';
|
||||
|
@ -231,20 +246,20 @@ class CommonUtils {
|
|||
assert(page.url().includes("/login/"));
|
||||
}
|
||||
|
||||
async ensure_enter_does_not_send(page) {
|
||||
async ensure_enter_does_not_send(page: Page): Promise<void> {
|
||||
await page.$eval("#enter_sends", (el) => {
|
||||
if (el.checked) {
|
||||
el.click();
|
||||
if ((el as HTMLInputElement).checked) {
|
||||
(el as HTMLInputElement).click();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async assert_compose_box_content(page, expected_value) {
|
||||
async assert_compose_box_content(page: Page, expected_value: string): Promise<void> {
|
||||
await page.waitForSelector("#compose-textarea");
|
||||
|
||||
const compose_box_element = await page.$("#compose-textarea");
|
||||
const compose_box_content = await page.evaluate(
|
||||
(element) => element.value,
|
||||
(element: HTMLTextAreaElement) => element.value,
|
||||
compose_box_element,
|
||||
);
|
||||
assert.equal(
|
||||
|
@ -254,9 +269,9 @@ class CommonUtils {
|
|||
);
|
||||
}
|
||||
|
||||
async wait_for_fully_processed_message(page, content) {
|
||||
async wait_for_fully_processed_message(page: Page, content: string): Promise<void> {
|
||||
await page.waitForFunction(
|
||||
(content) => {
|
||||
(content: string) => {
|
||||
/*
|
||||
The tricky part about making sure that
|
||||
a message has actually been fully processed
|
||||
|
@ -312,7 +327,7 @@ class CommonUtils {
|
|||
}
|
||||
|
||||
// Wait for any previous send to finish, then send a message.
|
||||
async send_message(page, type, params) {
|
||||
async send_message(page: Page, type: "stream" | "private", params: Message): Promise<void> {
|
||||
// If a message is outside the view, we do not need
|
||||
// to wait for it to be processed later.
|
||||
const outside_view = params.outside_view;
|
||||
|
@ -325,7 +340,7 @@ class CommonUtils {
|
|||
await page.keyboard.press("KeyC");
|
||||
} else if (type === "private") {
|
||||
await page.keyboard.press("KeyX");
|
||||
const recipients = params.recipient.split(", ");
|
||||
const recipients = params.recipient!.split(", ");
|
||||
for (const recipient of recipients) {
|
||||
await this.pm_recipient.set(page, recipient);
|
||||
}
|
||||
|
@ -366,7 +381,7 @@ class CommonUtils {
|
|||
await page.waitForSelector("#compose-textarea", {hidden: true});
|
||||
}
|
||||
|
||||
async send_multiple_messages(page, msgs) {
|
||||
async send_multiple_messages(page: Page, msgs: Message[]): Promise<void> {
|
||||
for (const msg of msgs) {
|
||||
await this.send_message(page, msg.stream !== undefined ? "stream" : "private", msg);
|
||||
}
|
||||
|
@ -381,10 +396,10 @@ class CommonUtils {
|
|||
*
|
||||
* The messages are sorted chronologically.
|
||||
*/
|
||||
async get_rendered_messages(page, table = "zhome") {
|
||||
return await page.evaluate((table) => {
|
||||
async get_rendered_messages(page: Page, table = "zhome"): Promise<[string, string[]][]> {
|
||||
return await page.evaluate((table: string) => {
|
||||
const $recipient_rows = $(`#${CSS.escape(table)}`).find(".recipient_row");
|
||||
return $recipient_rows.toArray().map((element) => {
|
||||
return $recipient_rows.toArray().map((element): [string, string[]] => {
|
||||
const $el = $(element);
|
||||
const stream_name = $el.find(".stream_label").text().trim();
|
||||
const topic_name = $el.find(".stream_topic a").text().trim();
|
||||
|
@ -399,7 +414,7 @@ class CommonUtils {
|
|||
const messages = $el
|
||||
.find(".message_row .message_content")
|
||||
.toArray()
|
||||
.map((message_row) => message_row.textContent.trim());
|
||||
.map((message_row) => message_row.textContent!.trim());
|
||||
|
||||
return [key, messages];
|
||||
});
|
||||
|
@ -411,7 +426,11 @@ class CommonUtils {
|
|||
// message is { "stream > topic": [messages] }.
|
||||
// The method will only check that all the messages in the
|
||||
// messages array passed exist in the order they are passed.
|
||||
async check_messages_sent(page, table, messages) {
|
||||
async check_messages_sent(
|
||||
page: Page,
|
||||
table: string,
|
||||
messages: [string, string[]][],
|
||||
): Promise<void> {
|
||||
await page.waitForSelector(`#${CSS.escape(table)}`, {visible: true});
|
||||
const rendered_messages = await this.get_rendered_messages(page, table);
|
||||
|
||||
|
@ -421,7 +440,7 @@ class CommonUtils {
|
|||
assert.deepStrictEqual(last_n_messages, messages);
|
||||
}
|
||||
|
||||
async manage_organization(page) {
|
||||
async manage_organization(page: Page): Promise<void> {
|
||||
const menu_selector = "#settings-dropdown";
|
||||
await page.waitForSelector(menu_selector, {visible: true});
|
||||
await page.click(menu_selector);
|
||||
|
@ -437,10 +456,15 @@ class CommonUtils {
|
|||
await page.click(organization_settings_data_section);
|
||||
}
|
||||
|
||||
async select_item_via_typeahead(page, field_selector, str, item) {
|
||||
async select_item_via_typeahead(
|
||||
page: Page,
|
||||
field_selector: string,
|
||||
str: string,
|
||||
item: string,
|
||||
): Promise<void> {
|
||||
console.log(`Looking in ${field_selector} to select ${str}, ${item}`);
|
||||
await page.evaluate(
|
||||
(field_selector, str, item) => {
|
||||
(field_selector: string, str: string, item: string) => {
|
||||
// Set the value and then send a bogus keyup event to trigger
|
||||
// the typeahead.
|
||||
$(field_selector)
|
||||
|
@ -464,26 +488,26 @@ class CommonUtils {
|
|||
);
|
||||
}
|
||||
|
||||
async run_test(test_function) {
|
||||
async run_test(test_function: (page: Page) => Promise<void>): Promise<void> {
|
||||
// Pass a page instance to test so we can take
|
||||
// a screenshot of it when the test fails.
|
||||
const browser = await this.ensure_browser();
|
||||
const page = await this.get_page();
|
||||
try {
|
||||
await test_function(page);
|
||||
} catch (error) {
|
||||
} catch (error: unknown) {
|
||||
console.log(error);
|
||||
|
||||
// Take a screenshot, and increment the screenshot_id.
|
||||
await this.screenshot(page, `failure-${this.screenshot_id}`);
|
||||
this.screenshot_id += 1;
|
||||
|
||||
await this.browser.close();
|
||||
await browser.close();
|
||||
process.exit(1);
|
||||
} finally {
|
||||
this.browser.close();
|
||||
await browser.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const common = new CommonUtils();
|
||||
module.exports = common;
|
||||
export default new CommonUtils();
|
|
@ -1,15 +1,15 @@
|
|||
"use strict";
|
||||
import {strict as assert} from "assert";
|
||||
|
||||
const {strict: assert} = require("assert");
|
||||
import type {Page} from "puppeteer";
|
||||
|
||||
const common = require("../puppeteer_lib/common");
|
||||
import common from "../puppeteer_lib/common";
|
||||
|
||||
const email = "alice@test.example.com";
|
||||
const subdomain = "testsubdomain";
|
||||
const organization_name = "Awesome Organization";
|
||||
const host = "zulipdev.com:9981";
|
||||
|
||||
async function realm_creation_tests(page) {
|
||||
async function realm_creation_tests(page: Page): Promise<void> {
|
||||
await page.goto("http://" + host + "/new/");
|
||||
|
||||
// submit the email for realm creation.
|
||||
|
@ -17,7 +17,7 @@ async function realm_creation_tests(page) {
|
|||
await page.type("#email", email);
|
||||
await Promise.all([
|
||||
page.waitForNavigation(),
|
||||
page.$eval("#send_confirm", (form) => form.submit()),
|
||||
page.$eval("#send_confirm", (form) => (form as HTMLFormElement).submit()),
|
||||
]);
|
||||
|
||||
// Make sure onfirmation email is sent.
|
||||
|
@ -27,8 +27,8 @@ async function realm_creation_tests(page) {
|
|||
await page.goto("http://" + host + "/confirmation_key/");
|
||||
|
||||
// Open the confirmation URL
|
||||
const page_content = await page.evaluate(() => document.querySelector("body").textContent);
|
||||
const confirmation_key = await JSON.parse(page_content).confirmation_key;
|
||||
const page_content = await page.evaluate(() => document.querySelector("body")!.textContent);
|
||||
const confirmation_key = await JSON.parse(page_content!).confirmation_key;
|
||||
const confirmation_url = "http://" + host + "/accounts/do_confirm/" + confirmation_key;
|
||||
await page.goto(confirmation_url);
|
||||
|
||||
|
@ -43,7 +43,9 @@ async function realm_creation_tests(page) {
|
|||
// Make sure the realm creation page is loaded correctly by
|
||||
// checking the text in <p> tag under pitch class is as expected.
|
||||
await page.waitForSelector(".pitch");
|
||||
const text_in_pitch = await page.evaluate(() => document.querySelector(".pitch p").textContent);
|
||||
const text_in_pitch = await page.evaluate(
|
||||
() => document.querySelector(".pitch p")!.textContent,
|
||||
);
|
||||
assert(text_in_pitch === "You’re almost there! We just need you to do one last thing.");
|
||||
|
||||
// fill the form.
|
||||
|
@ -56,9 +58,9 @@ async function realm_creation_tests(page) {
|
|||
};
|
||||
// For some reason, page.click() does not work this for particular checkbox
|
||||
// so use page.$eval here to call the .click method in the browser.
|
||||
await page.$eval("#realm_in_root_domain", (el) => el.click());
|
||||
await page.$eval("#realm_in_root_domain", (el) => (el as HTMLInputElement).click());
|
||||
await common.fill_form(page, "#registration", params);
|
||||
await page.$eval("#registration", (form) => form.submit());
|
||||
await page.$eval("#registration", (form) => (form as HTMLFormElement).submit());
|
||||
|
||||
// Check if realm is created and user is logged in by checking if
|
||||
// element of id `lightbox_overlay` exists.
|
|
@ -1,11 +0,0 @@
|
|||
"use strict";
|
||||
|
||||
const {test_credentials} = require("../../var/puppeteer/test_credentials");
|
||||
const common = require("../puppeteer_lib/common");
|
||||
|
||||
async function login_tests(page) {
|
||||
await common.log_in(page, test_credentials.default_user);
|
||||
await common.log_out(page);
|
||||
}
|
||||
|
||||
common.run_test(login_tests);
|
|
@ -0,0 +1,11 @@
|
|||
import type {Page} from "puppeteer";
|
||||
|
||||
import {test_credentials} from "../../var/puppeteer/test_credentials";
|
||||
import common from "../puppeteer_lib/common";
|
||||
|
||||
async function login_tests(page: Page): Promise<void> {
|
||||
await common.log_in(page, test_credentials.default_user);
|
||||
await common.log_out(page);
|
||||
}
|
||||
|
||||
common.run_test(login_tests);
|
|
@ -1,15 +1,15 @@
|
|||
"use strict";
|
||||
import {strict as assert} from "assert";
|
||||
|
||||
const {strict: assert} = require("assert");
|
||||
import type {Page} from "puppeteer";
|
||||
|
||||
const common = require("../puppeteer_lib/common");
|
||||
import common from "../puppeteer_lib/common";
|
||||
|
||||
async function get_stream_li(page, stream_name) {
|
||||
async function get_stream_li(page: Page, stream_name: string): Promise<string> {
|
||||
const stream_id = await common.get_stream_id(page, stream_name);
|
||||
return `#stream_filters [data-stream-id="${CSS.escape(stream_id)}"]`;
|
||||
return `#stream_filters [data-stream-id="${CSS.escape(stream_id.toString())}"]`;
|
||||
}
|
||||
|
||||
async function expect_home(page) {
|
||||
async function expect_home(page: Page): Promise<void> {
|
||||
await common.check_messages_sent(page, "zhome", [
|
||||
["Verona > test", ["verona test a", "verona test b"]],
|
||||
["Verona > other topic", ["verona other topic c"]],
|
||||
|
@ -22,7 +22,7 @@ async function expect_home(page) {
|
|||
]);
|
||||
}
|
||||
|
||||
async function expect_verona_stream(page) {
|
||||
async function expect_verona_stream(page: Page): Promise<void> {
|
||||
await page.waitForSelector("#zfilt", {visible: true});
|
||||
await common.check_messages_sent(page, "zfilt", [
|
||||
["Verona > test", ["verona test a", "verona test b"]],
|
||||
|
@ -32,7 +32,7 @@ async function expect_verona_stream(page) {
|
|||
assert.strictEqual(await page.title(), "Verona - Zulip Dev - Zulip");
|
||||
}
|
||||
|
||||
async function expect_verona_stream_test_topic(page) {
|
||||
async function expect_verona_stream_test_topic(page: Page): Promise<void> {
|
||||
await page.waitForSelector("#zfilt", {visible: true});
|
||||
await common.check_messages_sent(page, "zfilt", [
|
||||
["Verona > test", ["verona test a", "verona test b", "verona test d"]],
|
||||
|
@ -43,14 +43,14 @@ async function expect_verona_stream_test_topic(page) {
|
|||
);
|
||||
}
|
||||
|
||||
async function expect_verona_other_topic(page) {
|
||||
async function expect_verona_other_topic(page: Page): Promise<void> {
|
||||
await page.waitForSelector("#zfilt", {visible: true});
|
||||
await common.check_messages_sent(page, "zfilt", [
|
||||
["Verona > other topic", ["verona other topic c"]],
|
||||
]);
|
||||
}
|
||||
|
||||
async function expect_test_topic(page) {
|
||||
async function expect_test_topic(page: Page): Promise<void> {
|
||||
await page.waitForSelector("#zfilt", {visible: true});
|
||||
await common.check_messages_sent(page, "zfilt", [
|
||||
["Verona > test", ["verona test a", "verona test b"]],
|
||||
|
@ -59,7 +59,7 @@ async function expect_test_topic(page) {
|
|||
]);
|
||||
}
|
||||
|
||||
async function expect_huddle(page) {
|
||||
async function expect_huddle(page: Page): Promise<void> {
|
||||
await page.waitForSelector("#zfilt", {visible: true});
|
||||
await common.check_messages_sent(page, "zfilt", [
|
||||
["You and Cordelia Lear, King Hamlet", ["group pm a", "group pm b", "group pm d"]],
|
||||
|
@ -67,12 +67,12 @@ async function expect_huddle(page) {
|
|||
assert.strictEqual(await page.title(), "Cordelia Lear, King Hamlet - Zulip Dev - Zulip");
|
||||
}
|
||||
|
||||
async function expect_cordelia_private_narrow(page) {
|
||||
async function expect_cordelia_private_narrow(page: Page): Promise<void> {
|
||||
await page.waitForSelector("#zfilt", {visible: true});
|
||||
await common.check_messages_sent(page, "zfilt", [["You and Cordelia Lear", ["pm c", "pm e"]]]);
|
||||
}
|
||||
|
||||
async function un_narrow(page) {
|
||||
async function un_narrow(page: Page): Promise<void> {
|
||||
if (await page.evaluate(() => $(".message_comp").is(":visible"))) {
|
||||
await page.keyboard.press("Escape");
|
||||
}
|
||||
|
@ -81,11 +81,11 @@ async function un_narrow(page) {
|
|||
assert.strictEqual(await page.title(), "home - Zulip Dev - Zulip");
|
||||
}
|
||||
|
||||
async function un_narrow_by_clicking_org_icon(page) {
|
||||
async function un_narrow_by_clicking_org_icon(page: Page): Promise<void> {
|
||||
await page.click(".brand");
|
||||
}
|
||||
|
||||
async function test_navigations_from_home(page) {
|
||||
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 expect_verona_stream(page);
|
||||
|
@ -113,7 +113,13 @@ async function test_navigations_from_home(page) {
|
|||
await expect_home(page);
|
||||
}
|
||||
|
||||
async function search_and_check(page, search_str, item_to_select, check, expected_narrow_title) {
|
||||
async function search_and_check(
|
||||
page: Page,
|
||||
search_str: string,
|
||||
item_to_select: string,
|
||||
check: (page: Page) => Promise<void>,
|
||||
expected_narrow_title: string,
|
||||
): Promise<void> {
|
||||
await common.select_item_via_typeahead(page, "#search_query", search_str, item_to_select);
|
||||
await check(page);
|
||||
assert.strictEqual(await page.title(), expected_narrow_title);
|
||||
|
@ -121,7 +127,7 @@ async function search_and_check(page, search_str, item_to_select, check, expecte
|
|||
await expect_home(page);
|
||||
}
|
||||
|
||||
async function search_silent_user(page, str, item) {
|
||||
async function search_silent_user(page: Page, str: string, item: string): Promise<void> {
|
||||
await common.select_item_via_typeahead(page, "#search_query", str, item);
|
||||
await page.waitForSelector("#silent_user", {visible: true});
|
||||
const expect_message = "You haven't received any messages sent by this user yet!";
|
||||
|
@ -129,7 +135,7 @@ async function search_silent_user(page, str, item) {
|
|||
await un_narrow(page);
|
||||
}
|
||||
|
||||
async function expect_non_existing_user(page) {
|
||||
async function expect_non_existing_user(page: Page): Promise<void> {
|
||||
await page.waitForSelector("#non_existing_user", {visible: true});
|
||||
const expected_message = "This user does not exist!";
|
||||
assert.strictEqual(
|
||||
|
@ -138,7 +144,7 @@ async function expect_non_existing_user(page) {
|
|||
);
|
||||
}
|
||||
|
||||
async function expect_non_existing_users(page) {
|
||||
async function expect_non_existing_users(page: Page): Promise<void> {
|
||||
await page.waitForSelector("#non_existing_users", {visible: true});
|
||||
const expected_message = "One or more of these users do not exist!";
|
||||
assert.strictEqual(
|
||||
|
@ -147,13 +153,13 @@ async function expect_non_existing_users(page) {
|
|||
);
|
||||
}
|
||||
|
||||
async function search_non_existing_user(page, str, item) {
|
||||
async function search_non_existing_user(page: Page, str: string, item: string): Promise<void> {
|
||||
await common.select_item_via_typeahead(page, "#search_query", str, item);
|
||||
await expect_non_existing_user(page);
|
||||
await un_narrow(page);
|
||||
}
|
||||
|
||||
async function search_tests(page) {
|
||||
async function search_tests(page: Page): Promise<void> {
|
||||
await search_and_check(
|
||||
page,
|
||||
"Verona",
|
||||
|
@ -217,7 +223,7 @@ async function search_tests(page) {
|
|||
);
|
||||
}
|
||||
|
||||
async function expect_all_pm(page) {
|
||||
async function expect_all_pm(page: Page): Promise<void> {
|
||||
await page.waitForSelector("#zfilt", {visible: true});
|
||||
await common.check_messages_sent(page, "zfilt", [
|
||||
["You and Cordelia Lear, King Hamlet", ["group pm a", "group pm b"]],
|
||||
|
@ -232,7 +238,7 @@ async function expect_all_pm(page) {
|
|||
assert.strictEqual(await page.title(), "Private messages - Zulip Dev - Zulip");
|
||||
}
|
||||
|
||||
async function test_narrow_by_clicking_the_left_sidebar(page) {
|
||||
async function test_narrow_by_clicking_the_left_sidebar(page: Page): Promise<void> {
|
||||
console.log("Narrowing with left sidebar");
|
||||
|
||||
await page.click((await get_stream_li(page, "Verona")) + " a");
|
||||
|
@ -247,11 +253,11 @@ async function test_narrow_by_clicking_the_left_sidebar(page) {
|
|||
await un_narrow(page);
|
||||
}
|
||||
|
||||
async function arrow(page, direction) {
|
||||
await page.keyboard.press(`Arrow${direction}`);
|
||||
async function arrow(page: Page, direction: "Up" | "Down"): Promise<void> {
|
||||
await page.keyboard.press(({Up: "ArrowUp", Down: "ArrowDown"} as const)[direction]);
|
||||
}
|
||||
|
||||
async function test_search_venice(page) {
|
||||
async function test_search_venice(page: Page): Promise<void> {
|
||||
await page.evaluate(() => {
|
||||
$(".stream-list-filter")
|
||||
.expectOne()
|
||||
|
@ -279,7 +285,7 @@ async function test_search_venice(page) {
|
|||
await page.waitForSelector(".input-append.notdisplayed");
|
||||
}
|
||||
|
||||
async function test_stream_search_filters_stream_list(page) {
|
||||
async function test_stream_search_filters_stream_list(page: Page): Promise<void> {
|
||||
console.log("Search streams using left side bar");
|
||||
|
||||
await page.waitForSelector(".input-append.notdisplayed"); // Stream filter box invisible initially
|
||||
|
@ -342,22 +348,22 @@ async function test_stream_search_filters_stream_list(page) {
|
|||
await un_narrow(page);
|
||||
}
|
||||
|
||||
async function test_users_search(page) {
|
||||
async function test_users_search(page: Page): Promise<void> {
|
||||
console.log("Search users using right sidebar");
|
||||
async function assert_in_list(page, name) {
|
||||
async function assert_in_list(page: Page, name: string): Promise<void> {
|
||||
await page.waitForSelector(`#user_presences li [data-name="${CSS.escape(name)}"]`, {
|
||||
visible: true,
|
||||
});
|
||||
}
|
||||
|
||||
async function assert_selected(page, name) {
|
||||
async function assert_selected(page: Page, name: string): Promise<void> {
|
||||
await page.waitForSelector(
|
||||
`#user_presences li.highlighted_user [data-name="${CSS.escape(name)}"]`,
|
||||
{visible: true},
|
||||
);
|
||||
}
|
||||
|
||||
async function assert_not_selected(page, name) {
|
||||
async function assert_not_selected(page: Page, name: string): Promise<void> {
|
||||
await page.waitForSelector(
|
||||
`#user_presences li.highlighted_user [data-name="${CSS.escape(name)}"]`,
|
||||
{hidden: true},
|
||||
|
@ -406,7 +412,7 @@ async function test_users_search(page) {
|
|||
await expect_cordelia_private_narrow(page);
|
||||
}
|
||||
|
||||
async function message_basic_tests(page) {
|
||||
async function message_basic_tests(page: Page): Promise<void> {
|
||||
await common.log_in(page);
|
||||
|
||||
console.log("Sending messages");
|
|
@ -1,10 +1,10 @@
|
|||
"use strict";
|
||||
import {strict as assert} from "assert";
|
||||
|
||||
const {strict: assert} = require("assert");
|
||||
import type {Page} from "puppeteer";
|
||||
|
||||
const common = require("../puppeteer_lib/common");
|
||||
import common from "../puppeteer_lib/common";
|
||||
|
||||
async function check_compose_form_empty(page) {
|
||||
async function check_compose_form_empty(page: Page): Promise<void> {
|
||||
await common.check_form_contents(page, "#send_message_form", {
|
||||
stream_message_recipient_stream: "",
|
||||
stream_message_recipient_topic: "",
|
||||
|
@ -12,20 +12,20 @@ async function check_compose_form_empty(page) {
|
|||
});
|
||||
}
|
||||
|
||||
async function close_compose_box(page) {
|
||||
async function close_compose_box(page: Page): Promise<void> {
|
||||
await page.keyboard.press("Escape");
|
||||
await page.waitForSelector("#compose-textarea", {hidden: true});
|
||||
}
|
||||
|
||||
function get_message_xpath(text) {
|
||||
function get_message_xpath(text: string): string {
|
||||
return `//p[text()='${text}']`;
|
||||
}
|
||||
|
||||
function get_last_element(array) {
|
||||
function get_last_element<T>(array: T[]): T {
|
||||
return array.slice(-1)[0];
|
||||
}
|
||||
|
||||
async function test_send_messages(page) {
|
||||
async function test_send_messages(page: Page): Promise<void> {
|
||||
const initial_msgs_count = await page.evaluate(() => $("#zhome .message_row").length);
|
||||
|
||||
await common.send_multiple_messages(page, [
|
||||
|
@ -39,26 +39,26 @@ async function test_send_messages(page) {
|
|||
);
|
||||
}
|
||||
|
||||
async function test_stream_compose_keyboard_shortcut(page) {
|
||||
async function test_stream_compose_keyboard_shortcut(page: Page): Promise<void> {
|
||||
await page.keyboard.press("KeyC");
|
||||
await page.waitForSelector("#stream-message", {visible: true});
|
||||
await check_compose_form_empty(page);
|
||||
await close_compose_box(page);
|
||||
}
|
||||
|
||||
async function test_private_message_compose_shortcut(page) {
|
||||
async function test_private_message_compose_shortcut(page: Page): Promise<void> {
|
||||
await page.keyboard.press("KeyX");
|
||||
await page.waitForSelector("#private_message_recipient", {visible: true});
|
||||
await common.pm_recipient.expect(page, "");
|
||||
await close_compose_box(page);
|
||||
}
|
||||
|
||||
async function test_keyboard_shortcuts(page) {
|
||||
async function test_keyboard_shortcuts(page: Page): Promise<void> {
|
||||
await test_stream_compose_keyboard_shortcut(page);
|
||||
await test_private_message_compose_shortcut(page);
|
||||
}
|
||||
|
||||
async function test_reply_by_click_prepopulates_stream_topic_names(page) {
|
||||
async function test_reply_by_click_prepopulates_stream_topic_names(page: Page): Promise<void> {
|
||||
const stream_message = get_last_element(
|
||||
await page.$x(get_message_xpath("Compose stream reply test")),
|
||||
);
|
||||
|
@ -72,7 +72,9 @@ async function test_reply_by_click_prepopulates_stream_topic_names(page) {
|
|||
await close_compose_box(page);
|
||||
}
|
||||
|
||||
async function test_reply_by_click_prepopulates_private_message_recipient(page) {
|
||||
async function test_reply_by_click_prepopulates_private_message_recipient(
|
||||
page: Page,
|
||||
): Promise<void> {
|
||||
const private_message = get_last_element(
|
||||
await page.$x(get_message_xpath("Compose private message reply test")),
|
||||
);
|
||||
|
@ -85,7 +87,7 @@ async function test_reply_by_click_prepopulates_private_message_recipient(page)
|
|||
await close_compose_box(page);
|
||||
}
|
||||
|
||||
async function test_reply_with_r_shortcut(page) {
|
||||
async function test_reply_with_r_shortcut(page: Page): Promise<void> {
|
||||
// The last message(private) in the narrow is currently selected as a result of previous tests.
|
||||
// Now we go up and open compose box with r key.
|
||||
await page.keyboard.press("KeyK");
|
||||
|
@ -97,7 +99,7 @@ async function test_reply_with_r_shortcut(page) {
|
|||
});
|
||||
}
|
||||
|
||||
async function test_open_close_compose_box(page) {
|
||||
async function test_open_close_compose_box(page: Page): Promise<void> {
|
||||
await page.waitForSelector("#stream-message", {visible: true});
|
||||
await close_compose_box(page);
|
||||
await page.waitForSelector("#stream-message", {hidden: true});
|
||||
|
@ -108,12 +110,12 @@ async function test_open_close_compose_box(page) {
|
|||
await page.waitForSelector("#private-message", {hidden: true});
|
||||
}
|
||||
|
||||
async function test_narrow_to_private_messages_with_cordelia(page) {
|
||||
async function test_narrow_to_private_messages_with_cordelia(page: Page): Promise<void> {
|
||||
const you_and_cordelia_selector =
|
||||
'*[title="Narrow to your private messages with Cordelia Lear"]';
|
||||
// For some unknown reason page.click() isn't working here.
|
||||
await page.evaluate(
|
||||
(selector) => document.querySelector(selector).click(),
|
||||
(selector: string) => document.querySelector<HTMLElement>(selector)!.click(),
|
||||
you_and_cordelia_selector,
|
||||
);
|
||||
const cordelia_user_id = await common.get_user_id_from_name(page, "Cordelia Lear");
|
||||
|
@ -129,7 +131,7 @@ async function test_narrow_to_private_messages_with_cordelia(page) {
|
|||
await close_compose_box(page);
|
||||
}
|
||||
|
||||
async function test_send_multirecipient_pm_from_cordelia_pm_narrow(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)}')`;
|
||||
|
@ -143,8 +145,8 @@ async function test_send_multirecipient_pm_from_cordelia_pm_narrow(page) {
|
|||
await page.keyboard.press("Escape");
|
||||
|
||||
await page.waitForSelector("#zhome .message_row", {visible: true});
|
||||
await page.waitForFunction((selector) => $(selector).length !== 0, {}, pm_selector);
|
||||
await page.evaluate((selector) => {
|
||||
await page.waitForFunction((selector: string) => $(selector).length !== 0, {}, pm_selector);
|
||||
await page.evaluate((selector: string) => {
|
||||
$(selector).slice(-1)[0].click();
|
||||
}, pm_selector);
|
||||
await page.waitForSelector("#compose-textarea", {visible: true});
|
||||
|
@ -158,7 +160,7 @@ async function test_send_multirecipient_pm_from_cordelia_pm_narrow(page) {
|
|||
const markdown_preview_button = "#markdown_preview";
|
||||
const markdown_preview_hide_button = "#undo_markdown_preview";
|
||||
|
||||
async function test_markdown_preview_buttons_visibility(page) {
|
||||
async function test_markdown_preview_buttons_visibility(page: Page): Promise<void> {
|
||||
await page.waitForSelector(markdown_preview_button, {visible: true});
|
||||
await page.waitForSelector(markdown_preview_hide_button, {hidden: true});
|
||||
|
||||
|
@ -173,22 +175,22 @@ async function test_markdown_preview_buttons_visibility(page) {
|
|||
await page.waitForSelector(markdown_preview_hide_button, {hidden: true});
|
||||
}
|
||||
|
||||
async function test_markdown_preview_without_any_content(page) {
|
||||
async function test_markdown_preview_without_any_content(page: Page): Promise<void> {
|
||||
await page.click("#markdown_preview");
|
||||
await page.waitForSelector("#undo_markdown_preview", {visible: true});
|
||||
const markdown_preview_element = await page.$("#preview_content");
|
||||
assert.equal(
|
||||
await page.evaluate((element) => element.textContent, markdown_preview_element),
|
||||
await page.evaluate((element: Element) => element.textContent, markdown_preview_element),
|
||||
"Nothing to preview",
|
||||
);
|
||||
await page.click("#undo_markdown_preview");
|
||||
}
|
||||
|
||||
async function test_markdown_rendering(page) {
|
||||
async function test_markdown_rendering(page: Page): Promise<void> {
|
||||
await page.waitForSelector("#markdown_preview", {visible: true});
|
||||
let markdown_preview_element = await page.$("#preview_content");
|
||||
assert.equal(
|
||||
await page.evaluate((element) => element.textContent, markdown_preview_element),
|
||||
await page.evaluate((element: Element) => element.textContent, markdown_preview_element),
|
||||
"",
|
||||
);
|
||||
await common.fill_form(page, 'form[action^="/json/messages"]', {
|
||||
|
@ -201,18 +203,18 @@ async function test_markdown_rendering(page) {
|
|||
await page.waitForFunction(() => $("#preview_content").html() !== "");
|
||||
markdown_preview_element = await page.$("#preview_content");
|
||||
assert.equal(
|
||||
await page.evaluate((element) => element.innerHTML, markdown_preview_element),
|
||||
await page.evaluate((element: Element) => element.innerHTML, markdown_preview_element),
|
||||
expected_markdown_html,
|
||||
);
|
||||
}
|
||||
|
||||
async function test_markdown_preview(page) {
|
||||
async function test_markdown_preview(page: Page): Promise<void> {
|
||||
await test_markdown_preview_buttons_visibility(page);
|
||||
await test_markdown_preview_without_any_content(page);
|
||||
await test_markdown_rendering(page);
|
||||
}
|
||||
|
||||
async function compose_tests(page) {
|
||||
async function compose_tests(page: Page): Promise<void> {
|
||||
await common.log_in(page);
|
||||
await test_send_messages(page);
|
||||
await test_keyboard_shortcuts(page);
|
|
@ -1,43 +1,44 @@
|
|||
"use strict";
|
||||
import {strict as assert} from "assert";
|
||||
|
||||
const {strict: assert} = require("assert");
|
||||
import type {ElementHandle, Page} from "puppeteer";
|
||||
|
||||
const common = require("../puppeteer_lib/common");
|
||||
import common from "../puppeteer_lib/common";
|
||||
|
||||
async function user_checkbox(page, name) {
|
||||
async function user_checkbox(page: Page, name: string): Promise<string> {
|
||||
const user_id = await common.get_user_id_from_name(page, name);
|
||||
return `#user-checkboxes [data-user-id="${CSS.escape(user_id)}"]`;
|
||||
return `#user-checkboxes [data-user-id="${CSS.escape(user_id.toString())}"]`;
|
||||
}
|
||||
|
||||
async function user_span(page, name) {
|
||||
async function user_span(page: Page, name: string): Promise<string> {
|
||||
return (await user_checkbox(page, name)) + " input ~ span";
|
||||
}
|
||||
|
||||
async function stream_checkbox(page, stream_name) {
|
||||
async function stream_checkbox(page: Page, stream_name: string): Promise<string> {
|
||||
const stream_id = await common.get_stream_id(page, stream_name);
|
||||
return `#stream-checkboxes [data-stream-id="${CSS.escape(stream_id)}"]`;
|
||||
return `#stream-checkboxes [data-stream-id="${CSS.escape(stream_id.toString())}"]`;
|
||||
}
|
||||
|
||||
async function stream_span(page, stream_name) {
|
||||
async function stream_span(page: Page, stream_name: string): Promise<string> {
|
||||
return (await stream_checkbox(page, stream_name)) + " input ~ span";
|
||||
}
|
||||
|
||||
async function wait_for_checked(page, user_name, is_checked) {
|
||||
async function wait_for_checked(page: Page, user_name: string, is_checked: boolean): Promise<void> {
|
||||
const selector = await user_checkbox(page, user_name);
|
||||
await page.waitForFunction(
|
||||
(selector, is_checked) => $(selector).find("input")[0].checked === is_checked,
|
||||
(selector: string, is_checked: boolean) =>
|
||||
$(selector).find("input")[0].checked === is_checked,
|
||||
{},
|
||||
selector,
|
||||
is_checked,
|
||||
);
|
||||
}
|
||||
|
||||
async function stream_name_error(page) {
|
||||
async function stream_name_error(page: Page): Promise<string> {
|
||||
await page.waitForSelector("#stream_name_error", {visible: true});
|
||||
return await common.get_text_from_selector(page, "#stream_name_error");
|
||||
}
|
||||
|
||||
async function open_streams_modal(page) {
|
||||
async function open_streams_modal(page: Page): Promise<void> {
|
||||
const all_streams_selector = 'a[href="#streams/all"]';
|
||||
await page.waitForSelector(all_streams_selector, {visible: true});
|
||||
await page.click(all_streams_selector);
|
||||
|
@ -46,16 +47,16 @@ async function open_streams_modal(page) {
|
|||
assert(page.url().includes("#streams/all"));
|
||||
}
|
||||
|
||||
async function test_subscription_button_verona_stream(page) {
|
||||
async function test_subscription_button_verona_stream(page: Page): Promise<void> {
|
||||
const button_selector = "[data-stream-name='Verona'] .sub_unsub_button";
|
||||
const subscribed_selector = `${button_selector}.checked`;
|
||||
const unsubscribed_selector = `${button_selector}:not(.checked)`;
|
||||
|
||||
async function subscribed() {
|
||||
async function subscribed(): Promise<ElementHandle | null> {
|
||||
return await page.waitForSelector(subscribed_selector, {visible: true});
|
||||
}
|
||||
|
||||
async function unsubscribed() {
|
||||
async function unsubscribed(): Promise<ElementHandle | null> {
|
||||
return await page.waitForSelector(unsubscribed_selector, {visible: true});
|
||||
}
|
||||
|
||||
|
@ -66,57 +67,69 @@ async function test_subscription_button_verona_stream(page) {
|
|||
// We assume Verona is already subscribed, so the first line here
|
||||
// should happen immediately.
|
||||
button = await subscribed();
|
||||
button.click();
|
||||
button!.click();
|
||||
button = await unsubscribed();
|
||||
button.click();
|
||||
button!.click();
|
||||
button = await subscribed();
|
||||
button.click();
|
||||
button!.click();
|
||||
button = await unsubscribed();
|
||||
button.click();
|
||||
button!.click();
|
||||
button = await subscribed();
|
||||
}
|
||||
|
||||
async function click_create_new_stream(page, cordelia_checkbox, othello_checkbox) {
|
||||
async function click_create_new_stream(
|
||||
page: Page,
|
||||
cordelia_checkbox: string,
|
||||
othello_checkbox: string,
|
||||
): Promise<void> {
|
||||
await page.click("#add_new_subscription .create_stream_button");
|
||||
await page.waitForSelector(cordelia_checkbox, {visible: true});
|
||||
await page.waitForSelector(othello_checkbox, {visible: true});
|
||||
}
|
||||
|
||||
async function open_copy_from_stream_dropdown(page, scotland_checkbox, rome_checkbox) {
|
||||
async function open_copy_from_stream_dropdown(
|
||||
page: Page,
|
||||
scotland_checkbox: string,
|
||||
rome_checkbox: string,
|
||||
): Promise<void> {
|
||||
await page.click("#copy-from-stream-expand-collapse .control-label");
|
||||
await page.waitForSelector(scotland_checkbox, {visible: true});
|
||||
await page.waitForSelector(rome_checkbox, {visible: true});
|
||||
}
|
||||
|
||||
async function test_check_all_only_affects_visible_users(page) {
|
||||
async function test_check_all_only_affects_visible_users(page: Page): Promise<void> {
|
||||
await page.click(".subs_set_all_users");
|
||||
await wait_for_checked(page, "cordelia", false);
|
||||
await wait_for_checked(page, "othello", true);
|
||||
}
|
||||
|
||||
async function test_uncheck_all(page) {
|
||||
async function test_uncheck_all(page: Page): Promise<void> {
|
||||
await page.click(".subs_unset_all_users");
|
||||
await wait_for_checked(page, "othello", false);
|
||||
}
|
||||
|
||||
async function clear_ot_filter_with_backspace(page) {
|
||||
async function clear_ot_filter_with_backspace(page: Page): Promise<void> {
|
||||
await page.click(".add-user-list-filter");
|
||||
await page.keyboard.press("Backspace");
|
||||
await page.keyboard.press("Backspace");
|
||||
}
|
||||
|
||||
async function verify_filtered_users_are_visible_again(page, cordelia_checkbox, othello_checkbox) {
|
||||
async function verify_filtered_users_are_visible_again(
|
||||
page: Page,
|
||||
cordelia_checkbox: string,
|
||||
othello_checkbox: string,
|
||||
): Promise<void> {
|
||||
await page.waitForSelector(cordelia_checkbox, {visible: true});
|
||||
await page.waitForSelector(othello_checkbox, {visible: true});
|
||||
}
|
||||
|
||||
async function test_user_filter_ui(
|
||||
page,
|
||||
cordelia_checkbox,
|
||||
othello_checkbox,
|
||||
scotland_checkbox,
|
||||
rome_checkbox,
|
||||
) {
|
||||
page: Page,
|
||||
cordelia_checkbox: string,
|
||||
othello_checkbox: string,
|
||||
scotland_checkbox: string,
|
||||
rome_checkbox: string,
|
||||
): Promise<void> {
|
||||
await page.waitForSelector("form#stream_creation_form", {visible: true});
|
||||
|
||||
await common.fill_form(page, "form#stream_creation_form", {user_list_filter: "ot"});
|
||||
|
@ -135,7 +148,7 @@ async function test_user_filter_ui(
|
|||
await verify_filtered_users_are_visible_again(page, cordelia_checkbox, othello_checkbox);
|
||||
}
|
||||
|
||||
async function create_stream(page) {
|
||||
async function create_stream(page: Page): Promise<void> {
|
||||
await page.waitForXPath('//*[text()="Create stream"]', {visible: true});
|
||||
await common.fill_form(page, "form#stream_creation_form", {
|
||||
stream_name: "Puppeteer",
|
||||
|
@ -162,13 +175,13 @@ async function create_stream(page) {
|
|||
|
||||
// Assert subscriber count becomes 5(scotland(+4), cordelia(+1), othello(-1), Desdemona(+1)).
|
||||
await page.waitForFunction(
|
||||
(subscriber_count_selector) => $(subscriber_count_selector).text().trim() === "5",
|
||||
(subscriber_count_selector: string) => $(subscriber_count_selector).text().trim() === "5",
|
||||
{},
|
||||
subscriber_count_selector,
|
||||
);
|
||||
}
|
||||
|
||||
async function test_streams_with_empty_names_cannot_be_created(page) {
|
||||
async function test_streams_with_empty_names_cannot_be_created(page: Page): Promise<void> {
|
||||
await page.click("#add_new_subscription .create_stream_button");
|
||||
await page.waitForSelector("form#stream_creation_form", {visible: true});
|
||||
await common.fill_form(page, "form#stream_creation_form", {stream_name: " "});
|
||||
|
@ -176,7 +189,7 @@ async function test_streams_with_empty_names_cannot_be_created(page) {
|
|||
assert.strictEqual(await stream_name_error(page), "A stream needs to have a name");
|
||||
}
|
||||
|
||||
async function test_streams_with_duplicate_names_cannot_be_created(page) {
|
||||
async function test_streams_with_duplicate_names_cannot_be_created(page: Page): Promise<void> {
|
||||
await common.fill_form(page, "form#stream_creation_form", {stream_name: "Puppeteer"});
|
||||
await page.click("form#stream_creation_form button.button.sea-green");
|
||||
assert.strictEqual(await stream_name_error(page), "A stream with this name already exists");
|
||||
|
@ -185,7 +198,7 @@ async function test_streams_with_duplicate_names_cannot_be_created(page) {
|
|||
await page.click(cancel_button_selector);
|
||||
}
|
||||
|
||||
async function test_stream_creation(page) {
|
||||
async function test_stream_creation(page: Page): Promise<void> {
|
||||
const cordelia_checkbox = await user_checkbox(page, "cordelia");
|
||||
const othello_checkbox = await user_checkbox(page, "othello");
|
||||
const scotland_checkbox = await stream_checkbox(page, "Scotland");
|
||||
|
@ -205,7 +218,7 @@ async function test_stream_creation(page) {
|
|||
await test_streams_with_duplicate_names_cannot_be_created(page);
|
||||
}
|
||||
|
||||
async function test_streams_search_feature(page) {
|
||||
async function test_streams_search_feature(page: Page): Promise<void> {
|
||||
assert.strictEqual(await common.get_text_from_selector(page, "#search_stream_name"), "");
|
||||
const hidden_streams_selector = ".stream-row.notdisplayed .stream-name";
|
||||
assert.strictEqual(
|
||||
|
@ -235,7 +248,7 @@ async function test_streams_search_feature(page) {
|
|||
);
|
||||
}
|
||||
|
||||
async function subscriptions_tests(page) {
|
||||
async function subscriptions_tests(page: Page): Promise<void> {
|
||||
await common.log_in(page);
|
||||
await open_streams_modal(page);
|
||||
await test_subscription_button_verona_stream(page);
|
|
@ -1,17 +1,17 @@
|
|||
"use strict";
|
||||
import {strict as assert} from "assert";
|
||||
|
||||
const {strict: assert} = require("assert");
|
||||
import type {Page} from "puppeteer";
|
||||
|
||||
const common = require("../puppeteer_lib/common");
|
||||
import common from "../puppeteer_lib/common";
|
||||
|
||||
const message = "test star";
|
||||
|
||||
async function stars_count(page) {
|
||||
async function stars_count(page: Page): Promise<number> {
|
||||
return await page.evaluate(() => $("#zhome .fa-star:not(.empty-star)").length);
|
||||
}
|
||||
|
||||
async function toggle_test_star_message(page) {
|
||||
await page.evaluate((message) => {
|
||||
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");
|
||||
|
@ -26,7 +26,7 @@ async function toggle_test_star_message(page) {
|
|||
}, message);
|
||||
}
|
||||
|
||||
async function test_narrow_to_starred_messages(page) {
|
||||
async function test_narrow_to_starred_messages(page: Page): Promise<void> {
|
||||
await page.click('a[href^="#narrow/is/starred"]');
|
||||
await common.check_messages_sent(page, "zfilt", [["Verona > stars", [message]]]);
|
||||
|
||||
|
@ -35,7 +35,7 @@ async function test_narrow_to_starred_messages(page) {
|
|||
await page.waitForSelector("#zhome .message_row", {visible: true});
|
||||
}
|
||||
|
||||
async function stars_test(page) {
|
||||
async function stars_test(page: Page): Promise<void> {
|
||||
await common.log_in(page);
|
||||
await common.send_message(page, "stream", {
|
||||
stream: "Verona",
|
|
@ -1,8 +1,8 @@
|
|||
"use strict";
|
||||
import type {Page} from "puppeteer";
|
||||
|
||||
const common = require("../puppeteer_lib/common");
|
||||
import common from "../puppeteer_lib/common";
|
||||
|
||||
async function trigger_edit_last_message(page) {
|
||||
async function trigger_edit_last_message(page: Page): Promise<void> {
|
||||
await page.evaluate(() => {
|
||||
const msg = $("#zhome .message_row").last();
|
||||
msg.find(".info").trigger("click");
|
||||
|
@ -11,7 +11,7 @@ async function trigger_edit_last_message(page) {
|
|||
await page.waitForSelector(".message_edit_content", {visible: true});
|
||||
}
|
||||
|
||||
async function edit_stream_message(page, topic, content) {
|
||||
async function edit_stream_message(page: Page, topic: string, content: string): Promise<void> {
|
||||
await trigger_edit_last_message(page);
|
||||
|
||||
await page.evaluate(() => $(".message_edit_topic").val(""));
|
||||
|
@ -24,7 +24,7 @@ async function edit_stream_message(page, topic, content) {
|
|||
await common.wait_for_fully_processed_message(page, content);
|
||||
}
|
||||
|
||||
async function test_stream_message_edit(page) {
|
||||
async function test_stream_message_edit(page: Page): Promise<void> {
|
||||
await common.send_message(page, "stream", {
|
||||
stream: "Verona",
|
||||
topic: "edits",
|
||||
|
@ -36,7 +36,7 @@ async function test_stream_message_edit(page) {
|
|||
await common.check_messages_sent(page, "zhome", [["Verona > edited", ["test edited"]]]);
|
||||
}
|
||||
|
||||
async function test_edit_message_with_slash_me(page) {
|
||||
async function test_edit_message_with_slash_me(page: Page): Promise<void> {
|
||||
await common.send_message(page, "stream", {
|
||||
stream: "Verona",
|
||||
topic: "edits",
|
||||
|
@ -59,7 +59,7 @@ async function test_edit_message_with_slash_me(page) {
|
|||
);
|
||||
}
|
||||
|
||||
async function test_edit_private_message(page) {
|
||||
async function test_edit_private_message(page: Page): Promise<void> {
|
||||
await common.send_message(page, "private", {
|
||||
recipient: "cordelia@zulip.com",
|
||||
content: "test editing pm",
|
||||
|
@ -76,7 +76,7 @@ async function test_edit_private_message(page) {
|
|||
]);
|
||||
}
|
||||
|
||||
async function edit_tests(page) {
|
||||
async function edit_tests(page: Page): Promise<void> {
|
||||
await common.log_in(page);
|
||||
|
||||
await test_stream_message_edit(page);
|
|
@ -1,28 +1,28 @@
|
|||
"use strict";
|
||||
import {strict as assert} from "assert";
|
||||
|
||||
const {strict: assert} = require("assert");
|
||||
import type {Page} from "puppeteer";
|
||||
|
||||
const common = require("../puppeteer_lib/common");
|
||||
import common from "../puppeteer_lib/common";
|
||||
|
||||
async function wait_for_tab(page, tab) {
|
||||
async function wait_for_tab(page: Page, tab: string): Promise<void> {
|
||||
const tab_slector = `#${CSS.escape(tab)}.tab-pane.active`;
|
||||
await page.waitForSelector(tab_slector, {visible: true});
|
||||
}
|
||||
|
||||
async function navigate_to(page, click_target, tab) {
|
||||
async function navigate_to(page: Page, click_target: string, tab: string): Promise<void> {
|
||||
console.log("Visiting #" + click_target);
|
||||
await page.click(`a[href='#${CSS.escape(click_target)}']`);
|
||||
|
||||
await wait_for_tab(page, tab);
|
||||
}
|
||||
|
||||
async function open_menu(page) {
|
||||
async function open_menu(page: Page): Promise<void> {
|
||||
const menu_selector = "#settings-dropdown";
|
||||
await page.waitForSelector(menu_selector, {visible: true});
|
||||
await page.click(menu_selector);
|
||||
}
|
||||
|
||||
async function navigate_to_settings(page) {
|
||||
async function navigate_to_settings(page: Page): Promise<void> {
|
||||
console.log("Navigating to settings");
|
||||
|
||||
await open_menu(page);
|
||||
|
@ -36,7 +36,7 @@ async function navigate_to_settings(page) {
|
|||
await page.click("#settings_page .content-wrapper .exit");
|
||||
}
|
||||
|
||||
async function navigate_to_subscriptions(page) {
|
||||
async function navigate_to_subscriptions(page: Page): Promise<void> {
|
||||
console.log("Navigate to subscriptions");
|
||||
|
||||
await open_menu(page);
|
||||
|
@ -51,7 +51,7 @@ async function navigate_to_subscriptions(page) {
|
|||
await page.click("#subscription_overlay .exit");
|
||||
}
|
||||
|
||||
async function test_reload_hash(page) {
|
||||
async function test_reload_hash(page: Page): Promise<void> {
|
||||
const initial_page_load_time = await page.evaluate(() => page_params.page_load_time);
|
||||
console.log("initial load time: " + initial_page_load_time);
|
||||
|
||||
|
@ -70,7 +70,7 @@ async function test_reload_hash(page) {
|
|||
assert.strictEqual(hash, initial_hash, "Hash not preserved.");
|
||||
}
|
||||
|
||||
async function navigation_tests(page) {
|
||||
async function navigation_tests(page: Page): Promise<void> {
|
||||
await common.log_in(page);
|
||||
|
||||
await navigate_to_settings(page);
|
|
@ -1,10 +1,10 @@
|
|||
"use strict";
|
||||
import {strict as assert} from "assert";
|
||||
|
||||
const {strict: assert} = require("assert");
|
||||
import type {Page} from "puppeteer";
|
||||
|
||||
const common = require("../puppeteer_lib/common");
|
||||
import common from "../puppeteer_lib/common";
|
||||
|
||||
async function submit_notifications_stream_settings(page) {
|
||||
async function submit_notifications_stream_settings(page: Page): Promise<void> {
|
||||
await page.waitForSelector('#org-submit-notifications[data-status="unsaved"]', {visible: true});
|
||||
|
||||
const save_button = "#org-submit-notifications";
|
||||
|
@ -25,7 +25,7 @@ async function submit_notifications_stream_settings(page) {
|
|||
await page.waitForSelector("#org-submit-notifications", {hidden: true});
|
||||
}
|
||||
|
||||
async function test_change_new_stream_notifications_setting(page) {
|
||||
async function test_change_new_stream_notifications_setting(page: Page): Promise<void> {
|
||||
await page.click("#realm_notifications_stream_id_widget button.dropdown-toggle");
|
||||
await page.waitForSelector("#realm_notifications_stream_id_widget ul.dropdown-menu", {
|
||||
visible: true,
|
||||
|
@ -41,7 +41,7 @@ async function test_change_new_stream_notifications_setting(page) {
|
|||
|
||||
await common.wait_for_text(page, verona_in_dropdown, "Verona");
|
||||
await page.waitForSelector(verona_in_dropdown, {visible: true});
|
||||
await page.evaluate((selector) => $(selector).trigger("click"), verona_in_dropdown);
|
||||
await page.evaluate((selector: string) => $(selector).trigger("click"), verona_in_dropdown);
|
||||
|
||||
await submit_notifications_stream_settings(page);
|
||||
|
||||
|
@ -52,7 +52,7 @@ async function test_change_new_stream_notifications_setting(page) {
|
|||
await submit_notifications_stream_settings(page);
|
||||
}
|
||||
|
||||
async function test_change_signup_notifications_stream(page) {
|
||||
async function test_change_signup_notifications_stream(page: Page): Promise<void> {
|
||||
console.log('Changing signup notifications stream to Verona by filtering with "verona"');
|
||||
|
||||
await page.click("#id_realm_signup_notifications_stream_id > button.dropdown-toggle");
|
||||
|
@ -79,7 +79,7 @@ async function test_change_signup_notifications_stream(page) {
|
|||
await submit_notifications_stream_settings(page);
|
||||
}
|
||||
|
||||
async function test_permissions_change_save_worked(page) {
|
||||
async function test_permissions_change_save_worked(page: Page): Promise<void> {
|
||||
const saved_status = '#org-submit-stream-permissions[data-status="saved"]';
|
||||
await page.waitForSelector(saved_status, {
|
||||
visible: true,
|
||||
|
@ -87,7 +87,7 @@ async function test_permissions_change_save_worked(page) {
|
|||
await page.waitForSelector(saved_status, {hidden: true});
|
||||
}
|
||||
|
||||
async function submit_stream_permissions_change(page) {
|
||||
async function submit_stream_permissions_change(page: Page): Promise<void> {
|
||||
const save_button = "#org-submit-stream-permissions";
|
||||
await page.waitForSelector(save_button, {visible: true});
|
||||
assert.strictEqual(
|
||||
|
@ -100,49 +100,49 @@ async function submit_stream_permissions_change(page) {
|
|||
await test_permissions_change_save_worked(page);
|
||||
}
|
||||
|
||||
async function test_set_create_streams_to_admins_only(page) {
|
||||
async function test_set_create_streams_to_admins_only(page: Page): Promise<void> {
|
||||
console.log("Test setting create streams policy to 'admins only'.");
|
||||
await page.waitForSelector("#id_realm_create_stream_policy", {visible: true});
|
||||
await page.evaluate(() => $("#id_realm_create_stream_policy").val(2).trigger("change"));
|
||||
await submit_stream_permissions_change(page);
|
||||
}
|
||||
|
||||
async function test_set_create_streams_to_members_and_admins(page) {
|
||||
async function test_set_create_streams_to_members_and_admins(page: Page): Promise<void> {
|
||||
console.log("Test setting create streams policy to 'members and admins'.");
|
||||
await page.waitForSelector("#id_realm_create_stream_policy", {visible: true});
|
||||
await page.evaluate(() => $("#id_realm_create_stream_policy").val(1).trigger("change"));
|
||||
await submit_stream_permissions_change(page);
|
||||
}
|
||||
|
||||
async function test_set_create_streams_policy_to_full_members(page) {
|
||||
async function test_set_create_streams_policy_to_full_members(page: Page): Promise<void> {
|
||||
console.log("Test setting create streams policy to 'full members'.");
|
||||
await page.waitForSelector("#id_realm_create_stream_policy", {visible: true});
|
||||
await page.evaluate(() => $("#id_realm_create_stream_policy").val(3).trigger("change"));
|
||||
await submit_stream_permissions_change(page);
|
||||
}
|
||||
|
||||
async function test_set_invite_to_streams_policy_to_admins_only(page) {
|
||||
async function test_set_invite_to_streams_policy_to_admins_only(page: Page): Promise<void> {
|
||||
console.log("Test setting invite to streams policy to 'admins only'.");
|
||||
await page.waitForSelector("#id_realm_invite_to_stream_policy", {visible: true});
|
||||
await page.evaluate(() => $("#id_realm_invite_to_stream_policy").val(2).trigger("change"));
|
||||
await submit_stream_permissions_change(page);
|
||||
}
|
||||
|
||||
async function test_set_invite_to_streams_policy_to_members_and_admins(page) {
|
||||
async function test_set_invite_to_streams_policy_to_members_and_admins(page: Page): Promise<void> {
|
||||
console.log("Test setting invite to streams policy to 'members and admins'.");
|
||||
await page.waitForSelector("#id_realm_invite_to_stream_policy", {visible: true});
|
||||
await page.evaluate(() => $("#id_realm_invite_to_stream_policy").val(1).trigger("change"));
|
||||
await submit_stream_permissions_change(page);
|
||||
}
|
||||
|
||||
async function test_set_invite_to_streams_policy_to_full_members(page) {
|
||||
async function test_set_invite_to_streams_policy_to_full_members(page: Page): Promise<void> {
|
||||
console.log("Test setting invite to streams policy to 'full members'.");
|
||||
await page.waitForSelector("#id_realm_invite_to_stream_policy", {visible: true});
|
||||
await page.evaluate(() => $("#id_realm_invite_to_stream_policy").val(3).trigger("change"));
|
||||
await submit_stream_permissions_change(page);
|
||||
}
|
||||
|
||||
async function test_save_joining_organization_change_worked(page) {
|
||||
async function test_save_joining_organization_change_worked(page: Page): Promise<void> {
|
||||
const saved_status = '#org-submit-org-join[data-status="saved"]';
|
||||
await page.waitForSelector(saved_status, {
|
||||
visible: true,
|
||||
|
@ -150,7 +150,7 @@ async function test_save_joining_organization_change_worked(page) {
|
|||
await page.waitForSelector(saved_status, {hidden: true});
|
||||
}
|
||||
|
||||
async function submit_joining_organization_change(page) {
|
||||
async function submit_joining_organization_change(page: Page): Promise<void> {
|
||||
const save_button = "#org-submit-org-join";
|
||||
await page.waitForSelector(save_button, {visible: true});
|
||||
assert.strictEqual(
|
||||
|
@ -164,24 +164,28 @@ async function submit_joining_organization_change(page) {
|
|||
await test_save_joining_organization_change_worked(page);
|
||||
}
|
||||
|
||||
async function test_set_new_user_threshold_to_three_days(page) {
|
||||
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.evaluate(() =>
|
||||
$("#id_realm_waiting_period_setting").val("three_days").trigger("change"),
|
||||
);
|
||||
await submit_joining_organization_change(page);
|
||||
}
|
||||
|
||||
async function test_set_new_user_threshold_to_N_days(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.evaluate(() =>
|
||||
$("#id_realm_waiting_period_setting").val("custom_days").trigger("change"),
|
||||
);
|
||||
|
||||
const N = 10;
|
||||
await page.evaluate((N) => $("#id_realm_waiting_period_threshold").val(N), N);
|
||||
await page.evaluate((N: number) => $("#id_realm_waiting_period_threshold").val(N), N);
|
||||
await submit_joining_organization_change(page);
|
||||
}
|
||||
|
||||
async function test_organization_permissions(page) {
|
||||
async function test_organization_permissions(page: Page): Promise<void> {
|
||||
await page.click("li[data-section='organization-permissions']");
|
||||
|
||||
await test_set_create_streams_to_admins_only(page);
|
||||
|
@ -196,11 +200,11 @@ async function test_organization_permissions(page) {
|
|||
await test_set_new_user_threshold_to_N_days(page);
|
||||
}
|
||||
|
||||
async function test_add_emoji(page) {
|
||||
async function test_add_emoji(page: Page): Promise<void> {
|
||||
await common.fill_form(page, "form.admin-emoji-form", {name: "zulip logo"});
|
||||
|
||||
const emoji_upload_handle = await page.$("#emoji_file_input");
|
||||
await emoji_upload_handle.uploadFile("static/images/logo/zulip-icon-128x128.png");
|
||||
await emoji_upload_handle!.uploadFile("static/images/logo/zulip-icon-128x128.png");
|
||||
await page.click("#admin_emoji_submit");
|
||||
|
||||
const emoji_status = "div#admin-emoji-status";
|
||||
|
@ -219,14 +223,14 @@ async function test_add_emoji(page) {
|
|||
await page.waitForSelector("tr#emoji_zulip_logo img", {visible: true});
|
||||
}
|
||||
|
||||
async function test_delete_emoji(page) {
|
||||
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);
|
||||
}
|
||||
|
||||
async function test_custom_realm_emoji(page) {
|
||||
async function test_custom_realm_emoji(page: Page): Promise<void> {
|
||||
await page.click("li[data-section='emoji-settings']");
|
||||
await page.waitForSelector(".admin-emoji-form", {visible: true});
|
||||
|
||||
|
@ -234,8 +238,8 @@ async function test_custom_realm_emoji(page) {
|
|||
await test_delete_emoji(page);
|
||||
}
|
||||
|
||||
async function get_suggestions(page, str) {
|
||||
await page.evaluate((str) => {
|
||||
async function get_suggestions(page: Page, str: string): Promise<void> {
|
||||
await page.evaluate((str: string) => {
|
||||
$(".create_default_stream")
|
||||
.trigger("focus")
|
||||
.val(str)
|
||||
|
@ -243,8 +247,8 @@ async function get_suggestions(page, str) {
|
|||
}, str);
|
||||
}
|
||||
|
||||
async function select_from_suggestions(page, item) {
|
||||
await page.evaluate((item) => {
|
||||
async function select_from_suggestions(page: Page, item: string): Promise<void> {
|
||||
await page.evaluate((item: string) => {
|
||||
const tah = $(".create_default_stream").data().typeahead;
|
||||
tah.mouseenter({
|
||||
currentTarget: $(`.typeahead:visible li:contains("${CSS.escape(item)}")`)[0],
|
||||
|
@ -253,7 +257,11 @@ async function select_from_suggestions(page, item) {
|
|||
}, item);
|
||||
}
|
||||
|
||||
async function test_add_default_stream(page, stream_name, row) {
|
||||
async function test_add_default_stream(
|
||||
page: Page,
|
||||
stream_name: string,
|
||||
row: string,
|
||||
): Promise<void> {
|
||||
// It matches with all the stream names which has 'O' as a substring (Rome, Scotland, Verona
|
||||
// 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
|
||||
|
@ -265,28 +273,28 @@ async function test_add_default_stream(page, stream_name, row) {
|
|||
await page.waitForSelector(row, {visible: true});
|
||||
}
|
||||
|
||||
async function test_remove_default_stream(page, row) {
|
||||
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) => $(row).length === 0, {}, row);
|
||||
await page.waitForFunction((row: string) => $(row).length === 0, {}, row);
|
||||
}
|
||||
|
||||
async function test_default_streams(page) {
|
||||
async function test_default_streams(page: Page): Promise<void> {
|
||||
await page.click("li[data-section='default-streams-list']");
|
||||
await page.waitForSelector(".create_default_stream", {visible: true});
|
||||
|
||||
const stream_name = "Scotland";
|
||||
const stream_id = await common.get_stream_id(page, stream_name);
|
||||
const row = `.default_stream_row[data-stream-id='${CSS.escape(stream_id)}']`;
|
||||
const row = `.default_stream_row[data-stream-id='${CSS.escape(stream_id.toString())}']`;
|
||||
|
||||
await test_add_default_stream(page, stream_name, row);
|
||||
await test_remove_default_stream(page, row);
|
||||
}
|
||||
|
||||
async function test_upload_realm_icon_image(page) {
|
||||
async function test_upload_realm_icon_image(page: Page): Promise<void> {
|
||||
const upload_handle = await page.$("#realm-icon-upload-widget .image_file_input");
|
||||
await upload_handle.uploadFile("static/images/logo/zulip-icon-128x128.png");
|
||||
await upload_handle!.uploadFile("static/images/logo/zulip-icon-128x128.png");
|
||||
|
||||
await page.waitForSelector("#realm-icon-upload-widget .upload-spinner-background", {
|
||||
visible: true,
|
||||
|
@ -300,14 +308,14 @@ async function test_upload_realm_icon_image(page) {
|
|||
);
|
||||
}
|
||||
|
||||
async function delete_realm_icon(page) {
|
||||
async function delete_realm_icon(page: Page): Promise<void> {
|
||||
await page.click("li[data-section='organization-profile']");
|
||||
await page.click("#realm-icon-upload-widget .image-delete-button");
|
||||
|
||||
await page.waitForSelector("#realm-icon-upload-widget .image-delete-button", {visible: false});
|
||||
}
|
||||
|
||||
async function test_organization_profile(page) {
|
||||
async function test_organization_profile(page: Page): Promise<void> {
|
||||
await page.click("li[data-section='organization-profile']");
|
||||
const gravatar_selctor =
|
||||
'#realm-icon-upload-widget .image-block[src^="https://secure.gravatar.com/avatar/"]';
|
||||
|
@ -322,7 +330,7 @@ async function test_organization_profile(page) {
|
|||
await page.waitForSelector(gravatar_selctor, {visible: true});
|
||||
}
|
||||
|
||||
async function submit_default_user_settings(page) {
|
||||
async function submit_default_user_settings(page: Page): Promise<void> {
|
||||
assert.strictEqual(
|
||||
await common.get_text_from_selector(page, "#org-submit-user-defaults"),
|
||||
"Save changes",
|
||||
|
@ -332,7 +340,7 @@ async function submit_default_user_settings(page) {
|
|||
await page.waitForSelector(saved_status, {visible: false});
|
||||
}
|
||||
|
||||
async function test_change_organization_default_language(page) {
|
||||
async function test_change_organization_default_language(page: Page): Promise<void> {
|
||||
console.log("Changing realm default language");
|
||||
await page.click("li[data-section='organization-settings']");
|
||||
await page.waitForSelector("#id_realm_default_language", {visible: true});
|
||||
|
@ -341,7 +349,7 @@ async function test_change_organization_default_language(page) {
|
|||
await submit_default_user_settings(page);
|
||||
}
|
||||
|
||||
async function test_authentication_methods(page) {
|
||||
async function test_authentication_methods(page: Page): Promise<void> {
|
||||
await page.click("li[data-section='auth-methods']");
|
||||
await page.waitForSelector(".method_row[data-method='Google'] input[type='checkbox'] + span", {
|
||||
visible: true,
|
||||
|
@ -364,11 +372,13 @@ async function test_authentication_methods(page) {
|
|||
visible: true,
|
||||
});
|
||||
await page.waitForFunction(
|
||||
() => !$(".method_row[data-method='Google'] input[type='checkbox']")[0].checked,
|
||||
() =>
|
||||
!($(".method_row[data-method='Google'] input[type='checkbox']")[0] as HTMLInputElement)
|
||||
.checked,
|
||||
);
|
||||
}
|
||||
|
||||
async function admin_test(page) {
|
||||
async function admin_test(page: Page): Promise<void> {
|
||||
await common.log_in(page);
|
||||
|
||||
await common.manage_organization(page);
|
|
@ -1,10 +1,10 @@
|
|||
"use strict";
|
||||
import {strict as assert} from "assert";
|
||||
|
||||
const {strict: assert} = require("assert");
|
||||
import type {Page} from "puppeteer";
|
||||
|
||||
const common = require("../puppeteer_lib/common");
|
||||
import common from "../puppeteer_lib/common";
|
||||
|
||||
async function test_mention(page) {
|
||||
async function test_mention(page: Page): Promise<void> {
|
||||
await common.log_in(page);
|
||||
await page.keyboard.press("KeyC");
|
||||
await page.waitForSelector("#compose", {visible: true});
|
|
@ -1,14 +1,14 @@
|
|||
"use strict";
|
||||
import {strict as assert} from "assert";
|
||||
|
||||
const {strict: assert} = require("assert");
|
||||
import type {Page} from "puppeteer";
|
||||
|
||||
const common = require("../puppeteer_lib/common");
|
||||
import common from "../puppeteer_lib/common";
|
||||
|
||||
// These will be the row and edit form of the the custom profile we add.
|
||||
const profile_field_row = "#admin_profile_fields_table tr:nth-last-child(2)";
|
||||
const profile_field_form = "#admin_profile_fields_table tr:nth-last-child(1)";
|
||||
|
||||
async function test_add_new_profile_field(page) {
|
||||
async function test_add_new_profile_field(page: Page): Promise<void> {
|
||||
await page.waitForSelector(".admin-profile-field-form", {visible: true});
|
||||
await common.fill_form(page, "form.admin-profile-field-form", {
|
||||
name: "Teams",
|
||||
|
@ -28,7 +28,7 @@ async function test_add_new_profile_field(page) {
|
|||
);
|
||||
}
|
||||
|
||||
async function test_edit_profile_field(page) {
|
||||
async function test_edit_profile_field(page: Page): Promise<void> {
|
||||
await page.click(`${profile_field_row} button.open-edit-form`);
|
||||
await page.waitForSelector(`${profile_field_form} form.name-setting`, {visible: true});
|
||||
await common.fill_form(page, `${profile_field_form} form.name-setting`, {
|
||||
|
@ -44,7 +44,7 @@ async function test_edit_profile_field(page) {
|
|||
);
|
||||
}
|
||||
|
||||
async function test_delete_custom_profile_field(page) {
|
||||
async function test_delete_custom_profile_field(page: Page): Promise<void> {
|
||||
await page.click(`${profile_field_row} button.delete`);
|
||||
await page.waitForSelector("#admin-profile-field-status img", {visible: true});
|
||||
assert.strictEqual(
|
||||
|
@ -53,7 +53,7 @@ async function test_delete_custom_profile_field(page) {
|
|||
);
|
||||
}
|
||||
|
||||
async function test_custom_profile(page) {
|
||||
async function test_custom_profile(page: Page): Promise<void> {
|
||||
await common.log_in(page);
|
||||
await common.manage_organization(page);
|
||||
|
|
@ -1,10 +1,10 @@
|
|||
"use strict";
|
||||
import {strict as assert} from "assert";
|
||||
|
||||
const {strict: assert} = require("assert");
|
||||
import type {Page} from "puppeteer";
|
||||
|
||||
const common = require("../puppeteer_lib/common");
|
||||
import common from "../puppeteer_lib/common";
|
||||
|
||||
async function navigate_to_user_list(page) {
|
||||
async function navigate_to_user_list(page: Page): Promise<void> {
|
||||
const menu_selector = "#settings-dropdown";
|
||||
await page.waitForSelector(menu_selector, {visible: true});
|
||||
await page.click(menu_selector);
|
||||
|
@ -13,12 +13,12 @@ async function navigate_to_user_list(page) {
|
|||
await page.click("li[data-section='user-list-admin']");
|
||||
}
|
||||
|
||||
async function user_row(page, name) {
|
||||
async function user_row(page: Page, name: string): Promise<string> {
|
||||
const user_id = await common.get_user_id_from_name(page, name);
|
||||
return `.user_row[data-user-id="${CSS.escape(user_id)}"]`;
|
||||
return `.user_row[data-user-id="${CSS.escape(user_id.toString())}"]`;
|
||||
}
|
||||
|
||||
async function test_deactivate_user(page) {
|
||||
async function test_deactivate_user(page: Page): Promise<void> {
|
||||
const cordelia_user_row = await user_row(page, "cordelia");
|
||||
await page.waitForSelector(cordelia_user_row, {visible: true});
|
||||
await page.waitForSelector(cordelia_user_row + " .fa-user-times");
|
||||
|
@ -39,7 +39,7 @@ async function test_deactivate_user(page) {
|
|||
await page.waitForSelector("#user-field-status", {hidden: true});
|
||||
}
|
||||
|
||||
async function test_reactivate_user(page) {
|
||||
async function test_reactivate_user(page: Page): Promise<void> {
|
||||
let cordelia_user_row = await user_row(page, "cordelia");
|
||||
await page.waitForSelector(cordelia_user_row + ".deactivated_user");
|
||||
await page.waitForSelector(cordelia_user_row + " .fa-user-plus");
|
||||
|
@ -51,7 +51,7 @@ async function test_reactivate_user(page) {
|
|||
await page.waitForSelector("#user-field-status", {hidden: true});
|
||||
}
|
||||
|
||||
async function test_deactivated_users_section(page) {
|
||||
async function test_deactivated_users_section(page: Page): Promise<void> {
|
||||
const cordelia_user_row = await user_row(page, "cordelia");
|
||||
await test_deactivate_user(page);
|
||||
|
||||
|
@ -72,7 +72,7 @@ async function test_deactivated_users_section(page) {
|
|||
);
|
||||
}
|
||||
|
||||
async function test_bot_deactivation_and_reactivation(page) {
|
||||
async function test_bot_deactivation_and_reactivation(page: Page): Promise<void> {
|
||||
await page.click("li[data-section='bot-list-admin']");
|
||||
|
||||
const default_bot_user_row = await user_row(page, "Zulip Default Bot");
|
||||
|
@ -87,7 +87,7 @@ async function test_bot_deactivation_and_reactivation(page) {
|
|||
await page.waitForSelector(default_bot_user_row + " .fa-user-times");
|
||||
}
|
||||
|
||||
async function user_deactivation_test(page) {
|
||||
async function user_deactivation_test(page: Page): Promise<void> {
|
||||
await common.log_in(page);
|
||||
await navigate_to_user_list(page);
|
||||
await test_deactivate_user(page);
|
|
@ -1,22 +1,22 @@
|
|||
"use strict";
|
||||
import {strict as assert} from "assert";
|
||||
|
||||
const {strict: assert} = require("assert");
|
||||
import type {Page} from "puppeteer";
|
||||
|
||||
const common = require("../puppeteer_lib/common");
|
||||
import common from "../puppeteer_lib/common";
|
||||
|
||||
async function wait_for_drafts_to_dissapear(page) {
|
||||
async function wait_for_drafts_to_dissapear(page: Page): Promise<void> {
|
||||
await page.waitForFunction(
|
||||
() => $("#draft_overlay").length === 0 || $("#draft_overlay").css("opacity") === "0",
|
||||
);
|
||||
}
|
||||
|
||||
async function wait_for_drafts_to_appear(page) {
|
||||
async function wait_for_drafts_to_appear(page: Page): Promise<void> {
|
||||
await page.waitForFunction(
|
||||
() => $("#draft_overlay").length === 1 && $("#draft_overlay").css("opacity") === "1",
|
||||
);
|
||||
}
|
||||
|
||||
async function get_drafts_count(page) {
|
||||
async function get_drafts_count(page: Page): Promise<number> {
|
||||
return await page.$$eval(".draft-row", (drafts) => drafts.length);
|
||||
}
|
||||
|
||||
|
@ -24,7 +24,7 @@ const drafts_button = ".compose_drafts_button";
|
|||
const drafts_overlay = "#draft_overlay";
|
||||
const drafts_button_in_compose = "#below-compose-content .drafts-link";
|
||||
|
||||
async function test_empty_drafts(page) {
|
||||
async function test_empty_drafts(page: Page): Promise<void> {
|
||||
await page.waitForSelector(drafts_button, {visible: true});
|
||||
await page.click(drafts_button);
|
||||
|
||||
|
@ -36,7 +36,7 @@ async function test_empty_drafts(page) {
|
|||
await wait_for_drafts_to_dissapear(page);
|
||||
}
|
||||
|
||||
async function create_stream_message_draft(page) {
|
||||
async function create_stream_message_draft(page: Page): Promise<void> {
|
||||
console.log("Creating Stream Message Draft");
|
||||
await page.keyboard.press("KeyC");
|
||||
await page.waitForSelector("#stream-message", {visible: true});
|
||||
|
@ -48,7 +48,7 @@ async function create_stream_message_draft(page) {
|
|||
await page.click("#compose_close");
|
||||
}
|
||||
|
||||
async function create_private_message_draft(page) {
|
||||
async function create_private_message_draft(page: Page): Promise<void> {
|
||||
console.log("Creating private message draft");
|
||||
await page.keyboard.press("KeyX");
|
||||
await page.waitForSelector("#private_message_recipient", {visible: true});
|
||||
|
@ -58,7 +58,7 @@ async function create_private_message_draft(page) {
|
|||
await page.click("#compose_close");
|
||||
}
|
||||
|
||||
async function open_compose_markdown_preview(page) {
|
||||
async function open_compose_markdown_preview(page: Page): Promise<void> {
|
||||
const new_topic_button = "#left_bar_compose_stream_button_big";
|
||||
await page.waitForSelector(new_topic_button, {visible: true});
|
||||
await page.click(new_topic_button);
|
||||
|
@ -68,14 +68,14 @@ async function open_compose_markdown_preview(page) {
|
|||
await page.click(markdown_preview_button);
|
||||
}
|
||||
|
||||
async function open_drafts_through_compose(page) {
|
||||
async function open_drafts_through_compose(page: Page): Promise<void> {
|
||||
await open_compose_markdown_preview(page);
|
||||
await page.waitForSelector(drafts_button_in_compose, {visible: true});
|
||||
await page.click(drafts_button_in_compose);
|
||||
await wait_for_drafts_to_appear(page);
|
||||
}
|
||||
|
||||
async function test_previously_created_drafts_rendered(page) {
|
||||
async function test_previously_created_drafts_rendered(page: Page): Promise<void> {
|
||||
const drafts_count = await get_drafts_count(page);
|
||||
assert.strictEqual(drafts_count, 2, "Drafts improperly loaded.");
|
||||
assert.strictEqual(
|
||||
|
@ -109,7 +109,7 @@ async function test_previously_created_drafts_rendered(page) {
|
|||
);
|
||||
}
|
||||
|
||||
async function test_restore_message_draft(page) {
|
||||
async function test_restore_message_draft(page: Page): Promise<void> {
|
||||
console.log("Restoring Stream Message Draft");
|
||||
await page.click("#drafts_table .message_row:not(.private-message) .restore-draft");
|
||||
await wait_for_drafts_to_dissapear(page);
|
||||
|
@ -127,7 +127,7 @@ async function test_restore_message_draft(page) {
|
|||
);
|
||||
}
|
||||
|
||||
async function edit_stream_message_draft(page) {
|
||||
async function edit_stream_message_draft(page: Page): Promise<void> {
|
||||
await common.fill_form(page, "form#send_message_form", {
|
||||
stream_message_recipient_stream: "all",
|
||||
stream_message_recipient_topic: "tests",
|
||||
|
@ -136,7 +136,7 @@ async function edit_stream_message_draft(page) {
|
|||
await page.click("#compose_close");
|
||||
}
|
||||
|
||||
async function test_edited_draft_message(page) {
|
||||
async function test_edited_draft_message(page: Page): Promise<void> {
|
||||
await page.waitForSelector(drafts_button, {visible: true});
|
||||
await page.click(drafts_button);
|
||||
|
||||
|
@ -161,7 +161,7 @@ async function test_edited_draft_message(page) {
|
|||
);
|
||||
}
|
||||
|
||||
async function test_restore_private_message_draft(page) {
|
||||
async function test_restore_private_message_draft(page: Page): Promise<void> {
|
||||
console.log("Restoring private message draft.");
|
||||
await page.click("#drafts_table .message_row.private-message .restore-draft");
|
||||
await wait_for_drafts_to_dissapear(page);
|
||||
|
@ -180,7 +180,7 @@ async function test_restore_private_message_draft(page) {
|
|||
await page.click("#compose_close");
|
||||
}
|
||||
|
||||
async function test_delete_draft(page) {
|
||||
async function test_delete_draft(page: Page): Promise<void> {
|
||||
console.log("Deleting draft");
|
||||
await page.waitForSelector(drafts_button, {visible: true});
|
||||
await page.click(drafts_button);
|
||||
|
@ -194,7 +194,7 @@ async function test_delete_draft(page) {
|
|||
await page.click("body");
|
||||
}
|
||||
|
||||
async function test_save_draft_by_reloading(page) {
|
||||
async function test_save_draft_by_reloading(page: Page): Promise<void> {
|
||||
console.log("Saving draft by reloading.");
|
||||
await page.keyboard.press("KeyX");
|
||||
await page.waitForSelector("#private-message", {visible: true});
|
||||
|
@ -229,7 +229,7 @@ async function test_save_draft_by_reloading(page) {
|
|||
);
|
||||
}
|
||||
|
||||
async function test_delete_draft_on_sending(page) {
|
||||
async function test_delete_draft_on_sending(page: Page): Promise<void> {
|
||||
await page.click("#drafts_table .message_row.private-message .restore-draft");
|
||||
await wait_for_drafts_to_dissapear(page);
|
||||
await page.waitForSelector("#private-message", {visible: true});
|
||||
|
@ -245,7 +245,7 @@ async function test_delete_draft_on_sending(page) {
|
|||
await page.waitForSelector("#drafts_table .message_row.private-message", {hidden: true});
|
||||
}
|
||||
|
||||
async function drafts_test(page) {
|
||||
async function drafts_test(page: Page): Promise<void> {
|
||||
await common.log_in(page);
|
||||
|
||||
await test_empty_drafts(page);
|
|
@ -1,8 +1,8 @@
|
|||
"use strict";
|
||||
import type {Page} from "puppeteer";
|
||||
|
||||
const common = require("../puppeteer_lib/common");
|
||||
import common from "../puppeteer_lib/common";
|
||||
|
||||
async function click_delete_and_return_last_msg_id(page) {
|
||||
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(".info").trigger("click");
|
||||
|
@ -11,7 +11,7 @@ async function click_delete_and_return_last_msg_id(page) {
|
|||
});
|
||||
}
|
||||
|
||||
async function delete_message_test(page) {
|
||||
async function delete_message_test(page: Page): Promise<void> {
|
||||
await common.log_in(page);
|
||||
const messages_quantitiy = await page.evaluate(() => $("#zhome .message_row").length);
|
||||
const last_message_id = await click_delete_and_return_last_msg_id(page);
|
||||
|
@ -24,12 +24,12 @@ async function delete_message_test(page) {
|
|||
await page.waitForSelector("#do_delete_message_button", {hidden: true});
|
||||
|
||||
await page.waitForFunction(
|
||||
(expected_length) => $("#zhome .message_row").length === expected_length,
|
||||
(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});
|
||||
await page.waitForSelector("#do_delete_message_spinner .loading_indicator_spinner", {
|
||||
hidden: true,
|
||||
});
|
|
@ -1,13 +1,17 @@
|
|||
"use strict";
|
||||
import {strict as assert} from "assert";
|
||||
|
||||
const {strict: assert} = require("assert");
|
||||
import type {Page} from "puppeteer";
|
||||
|
||||
const common = require("../puppeteer_lib/common");
|
||||
import common from "../puppeteer_lib/common";
|
||||
|
||||
async function copy_messages(page, start_message, end_message) {
|
||||
async function copy_messages(
|
||||
page: Page,
|
||||
start_message: string,
|
||||
end_message: string,
|
||||
): Promise<string[]> {
|
||||
return await page.evaluate(
|
||||
(start_message, end_message) => {
|
||||
function get_message_node(message) {
|
||||
(start_message: string, end_message: string) => {
|
||||
function get_message_node(message: string): Element {
|
||||
return $(`.message_row .message_content:contains("${CSS.escape(message)}")`).get(0);
|
||||
}
|
||||
|
||||
|
@ -15,8 +19,8 @@ async function copy_messages(page, start_message, end_message) {
|
|||
const selectedRange = document.createRange();
|
||||
selectedRange.setStartAfter(get_message_node(start_message));
|
||||
selectedRange.setEndBefore(get_message_node(end_message));
|
||||
window.getSelection().removeAllRanges();
|
||||
window.getSelection().addRange(selectedRange);
|
||||
window.getSelection()!.removeAllRanges();
|
||||
window.getSelection()!.addRange(selectedRange);
|
||||
|
||||
// Remove existing copy/paste divs, which may linger from the previous
|
||||
// example. (The code clears these out with a zero-second timeout, which
|
||||
|
@ -31,32 +35,32 @@ async function copy_messages(page, start_message, end_message) {
|
|||
return temp_div
|
||||
.children("p")
|
||||
.get()
|
||||
.map((p) => p.textContent);
|
||||
.map((p) => p.textContent!);
|
||||
},
|
||||
start_message,
|
||||
end_message,
|
||||
);
|
||||
}
|
||||
|
||||
async function test_copying_first_message_from_topic(page) {
|
||||
async function test_copying_first_message_from_topic(page: Page): Promise<void> {
|
||||
const actual_copied_lines = await copy_messages(page, "copy paste test C", "copy paste test C");
|
||||
const expected_copied_lines = [];
|
||||
const expected_copied_lines: string[] = [];
|
||||
assert.deepStrictEqual(actual_copied_lines, expected_copied_lines);
|
||||
}
|
||||
|
||||
async function test_copying_last_message_from_topic(page) {
|
||||
async function test_copying_last_message_from_topic(page: Page): Promise<void> {
|
||||
const actual_copied_lines = await copy_messages(page, "copy paste test E", "copy paste test E");
|
||||
const expected_copied_lines = [];
|
||||
const expected_copied_lines: string[] = [];
|
||||
assert.deepStrictEqual(actual_copied_lines, expected_copied_lines);
|
||||
}
|
||||
|
||||
async function test_copying_first_two_messages_from_topic(page) {
|
||||
async function test_copying_first_two_messages_from_topic(page: Page): Promise<void> {
|
||||
const actual_copied_lines = await copy_messages(page, "copy paste test C", "copy paste test D");
|
||||
const expected_copied_lines = ["Desdemona: copy paste test C", "Desdemona: copy paste test D"];
|
||||
assert.deepStrictEqual(actual_copied_lines, expected_copied_lines);
|
||||
}
|
||||
|
||||
async function test_copying_all_messages_from_topic(page) {
|
||||
async function test_copying_all_messages_from_topic(page: Page): Promise<void> {
|
||||
const actual_copied_lines = await copy_messages(page, "copy paste test C", "copy paste test E");
|
||||
const expected_copied_lines = [
|
||||
"Desdemona: copy paste test C",
|
||||
|
@ -66,7 +70,7 @@ async function test_copying_all_messages_from_topic(page) {
|
|||
assert.deepStrictEqual(actual_copied_lines, expected_copied_lines);
|
||||
}
|
||||
|
||||
async function test_copying_last_from_prev_first_from_next(page) {
|
||||
async function test_copying_last_from_prev_first_from_next(page: Page): Promise<void> {
|
||||
const actual_copied_lines = await copy_messages(page, "copy paste test B", "copy paste test C");
|
||||
const expected_copied_lines = [
|
||||
"Verona > copy-paste-topic #1 Today",
|
||||
|
@ -77,7 +81,7 @@ async function test_copying_last_from_prev_first_from_next(page) {
|
|||
assert.deepStrictEqual(actual_copied_lines, expected_copied_lines);
|
||||
}
|
||||
|
||||
async function test_copying_last_from_prev_all_from_next(page) {
|
||||
async function test_copying_last_from_prev_all_from_next(page: Page): Promise<void> {
|
||||
const actual_copied_lines = await copy_messages(page, "copy paste test B", "copy paste test E");
|
||||
const expected_copied_lines = [
|
||||
"Verona > copy-paste-topic #1 Today",
|
||||
|
@ -90,7 +94,7 @@ async function test_copying_last_from_prev_all_from_next(page) {
|
|||
assert.deepStrictEqual(actual_copied_lines, expected_copied_lines);
|
||||
}
|
||||
|
||||
async function test_copying_all_from_prev_first_from_next(page) {
|
||||
async function test_copying_all_from_prev_first_from_next(page: Page): Promise<void> {
|
||||
const actual_copied_lines = await copy_messages(page, "copy paste test A", "copy paste test C");
|
||||
const expected_copied_lines = [
|
||||
"Verona > copy-paste-topic #1 Today",
|
||||
|
@ -102,7 +106,7 @@ async function test_copying_all_from_prev_first_from_next(page) {
|
|||
assert.deepStrictEqual(actual_copied_lines, expected_copied_lines);
|
||||
}
|
||||
|
||||
async function test_copying_messages_from_several_topics(page) {
|
||||
async function test_copying_messages_from_several_topics(page: Page): Promise<void> {
|
||||
const actual_copied_lines = await copy_messages(page, "copy paste test B", "copy paste test F");
|
||||
const expected_copied_lines = [
|
||||
"Verona > copy-paste-topic #1 Today",
|
||||
|
@ -117,7 +121,7 @@ async function test_copying_messages_from_several_topics(page) {
|
|||
assert.deepStrictEqual(actual_copied_lines, expected_copied_lines);
|
||||
}
|
||||
|
||||
async function copy_paste_test(page) {
|
||||
async function copy_paste_test(page: Page): Promise<void> {
|
||||
await common.log_in(page);
|
||||
|
||||
await common.send_multiple_messages(page, [
|
|
@ -1,10 +1,10 @@
|
|||
"use strict";
|
||||
import {strict as assert} from "assert";
|
||||
|
||||
const {strict: assert} = require("assert");
|
||||
import type {Page} from "puppeteer";
|
||||
|
||||
const common = require("../puppeteer_lib/common");
|
||||
import common from "../puppeteer_lib/common";
|
||||
|
||||
async function test_add_linkifier(page) {
|
||||
async function test_add_linkifier(page: Page): Promise<void> {
|
||||
await page.waitForSelector(".admin-filter-form", {visible: true});
|
||||
await common.fill_form(page, "form.admin-filter-form", {
|
||||
pattern: "#(?P<id>[0-9]+)",
|
||||
|
@ -31,12 +31,12 @@ async function test_add_linkifier(page) {
|
|||
);
|
||||
}
|
||||
|
||||
async function test_delete_linkifier(page) {
|
||||
async function test_delete_linkifier(page: Page): Promise<void> {
|
||||
await page.click(".filter_row button");
|
||||
await page.waitForSelector(".filter_row", {hidden: true});
|
||||
}
|
||||
|
||||
async function test_invalid_linkifier_pattern(page) {
|
||||
async function test_invalid_linkifier_pattern(page: Page): Promise<void> {
|
||||
await page.waitForSelector(".admin-filter-form", {visible: true});
|
||||
await common.fill_form(page, "form.admin-filter-form", {
|
||||
pattern: "a$",
|
||||
|
@ -51,7 +51,7 @@ async function test_invalid_linkifier_pattern(page) {
|
|||
);
|
||||
}
|
||||
|
||||
async function realm_linkifier_test(page) {
|
||||
async function realm_linkifier_test(page: Page): Promise<void> {
|
||||
await common.log_in(page);
|
||||
await common.manage_organization(page);
|
||||
await page.click("li[data-section='filter-settings']");
|
|
@ -1,23 +1,23 @@
|
|||
"use strict";
|
||||
import {strict as assert} from "assert";
|
||||
|
||||
const {strict: assert} = require("assert");
|
||||
import type {Page} from "puppeteer";
|
||||
|
||||
const {test_credentials} = require("../../var/puppeteer/test_credentials");
|
||||
const common = require("../puppeteer_lib/common");
|
||||
import {test_credentials} from "../../var/puppeteer/test_credentials";
|
||||
import common from "../puppeteer_lib/common";
|
||||
|
||||
const OUTGOING_WEBHOOK_BOT_TYPE = "3";
|
||||
const GENERIC_BOT_TYPE = "1";
|
||||
|
||||
const zuliprc_regex = /^data:application\/octet-stream;charset=utf-8,\[api]\nemail=.+\nkey=.+\nsite=.+\n$/;
|
||||
|
||||
async function get_decoded_url_in_selector(page, selector) {
|
||||
async function get_decoded_url_in_selector(page: Page, selector: string): Promise<string> {
|
||||
return await page.evaluate(
|
||||
(selector) => decodeURIComponent($(selector).attr("href")),
|
||||
(selector: string) => decodeURIComponent($(selector).attr("href")!),
|
||||
selector,
|
||||
);
|
||||
}
|
||||
|
||||
async function open_settings(page) {
|
||||
async function open_settings(page: Page): Promise<void> {
|
||||
const menu_selector = "#settings-dropdown";
|
||||
await page.waitForSelector(menu_selector, {visible: true});
|
||||
await page.click(menu_selector);
|
||||
|
@ -31,7 +31,7 @@ async function open_settings(page) {
|
|||
assert(page_url.includes("/#settings/"), `Page url: ${page_url} does not contain /#settings/`);
|
||||
}
|
||||
|
||||
async function test_change_full_name(page) {
|
||||
async function test_change_full_name(page: Page): Promise<void> {
|
||||
await page.click("#change_full_name");
|
||||
|
||||
const change_full_name_button_selector = "#change_full_name_button";
|
||||
|
@ -39,7 +39,7 @@ async function test_change_full_name(page) {
|
|||
|
||||
const full_name_input_selector = 'input[name="full_name"]';
|
||||
await page.$eval(full_name_input_selector, (el) => {
|
||||
el.value = "";
|
||||
(el as HTMLInputElement).value = "";
|
||||
});
|
||||
await page.waitForFunction(() => $(":focus").attr("id") === "change_full_name_modal");
|
||||
await page.type(full_name_input_selector, "New name");
|
||||
|
@ -47,7 +47,7 @@ async function test_change_full_name(page) {
|
|||
await page.waitForFunction(() => $("#change_full_name").text().trim() === "New name");
|
||||
}
|
||||
|
||||
async function test_change_password(page) {
|
||||
async function test_change_password(page: Page): Promise<void> {
|
||||
await page.click("#change_password");
|
||||
|
||||
const change_password_button_selector = "#change_password_button";
|
||||
|
@ -62,7 +62,7 @@ async function test_change_password(page) {
|
|||
await page.waitForFunction(() => $("#change_password_modal").attr("aria-hidden") === "true");
|
||||
}
|
||||
|
||||
async function test_get_api_key(page) {
|
||||
async function test_get_api_key(page: Page): Promise<void> {
|
||||
const show_change_api_key_selector = "#api_key_button";
|
||||
await page.click(show_change_api_key_selector);
|
||||
|
||||
|
@ -85,7 +85,7 @@ async function test_get_api_key(page) {
|
|||
await page.click("#api_key_modal .close");
|
||||
}
|
||||
|
||||
async function test_webhook_bot_creation(page) {
|
||||
async function test_webhook_bot_creation(page: Page): Promise<void> {
|
||||
await common.fill_form(page, "#create_bot_form", {
|
||||
bot_name: "Bot 1",
|
||||
bot_short_name: "1",
|
||||
|
@ -111,7 +111,7 @@ async function test_webhook_bot_creation(page) {
|
|||
);
|
||||
}
|
||||
|
||||
async function test_normal_bot_creation(page) {
|
||||
async function test_normal_bot_creation(page: Page): Promise<void> {
|
||||
await page.click(".add-a-new-bot-tab");
|
||||
await page.waitForSelector("#create_bot_button", {visible: true});
|
||||
|
||||
|
@ -134,7 +134,7 @@ async function test_normal_bot_creation(page) {
|
|||
assert(zuliprc_regex.test(zuliprc_decoded_url), "Incorrect zuliprc format for bot.");
|
||||
}
|
||||
|
||||
async function test_botserverrc(page) {
|
||||
async function test_botserverrc(page: Page): Promise<void> {
|
||||
await page.click("#download_botserverrc");
|
||||
await page.waitForSelector('#download_botserverrc[href^="data:application"]', {visible: true});
|
||||
const botserverrc_decoded_url = await get_decoded_url_in_selector(
|
||||
|
@ -145,7 +145,7 @@ async function test_botserverrc(page) {
|
|||
assert(botserverrc_regex.test(botserverrc_decoded_url), "Incorrect botserverrc format.");
|
||||
}
|
||||
|
||||
async function test_edit_bot_form(page) {
|
||||
async function test_edit_bot_form(page: Page): Promise<void> {
|
||||
const bot1_email = "1-bot@zulip.testserver";
|
||||
const bot1_edit_btn = `.open_edit_bot_form[data-email="${CSS.escape(bot1_email)}"]`;
|
||||
await page.click(bot1_edit_btn);
|
||||
|
@ -164,14 +164,14 @@ async function test_edit_bot_form(page) {
|
|||
|
||||
const bot1_name_selector = `.details:has(${bot1_edit_btn}) .name`;
|
||||
await page.waitForFunction(
|
||||
(bot1_name_selector) => $(bot1_name_selector).text() !== "Bot 1",
|
||||
(bot1_name_selector: string) => $(bot1_name_selector).text() !== "Bot 1",
|
||||
{},
|
||||
bot1_name_selector,
|
||||
);
|
||||
assert.strictEqual(await common.get_text_from_selector(page, bot1_name_selector), "Bot one");
|
||||
}
|
||||
|
||||
async function test_your_bots_section(page) {
|
||||
async function test_your_bots_section(page: Page): Promise<void> {
|
||||
await page.click('[data-section="your-bots"]');
|
||||
await test_webhook_bot_creation(page);
|
||||
await test_normal_bot_creation(page);
|
||||
|
@ -181,55 +181,61 @@ async function test_your_bots_section(page) {
|
|||
|
||||
const alert_word_status_selector = "#alert_word_status";
|
||||
|
||||
async function add_alert_word(page, word) {
|
||||
async function add_alert_word(page: Page, word: string): Promise<void> {
|
||||
await page.type("#create_alert_word_name", word);
|
||||
await page.click("#create_alert_word_button");
|
||||
}
|
||||
|
||||
async function check_alert_word_added(page, word) {
|
||||
async function check_alert_word_added(page: Page, word: string): Promise<void> {
|
||||
const added_alert_word_selector = `.alert-word-item[data-word='${CSS.escape(word)}']`;
|
||||
await page.waitForSelector(added_alert_word_selector, {visible: true});
|
||||
}
|
||||
|
||||
async function get_alert_words_status_text(page) {
|
||||
async function get_alert_words_status_text(page: Page): Promise<string> {
|
||||
await page.waitForSelector(alert_word_status_selector, {visible: true});
|
||||
const status_text = await common.get_text_from_selector(page, ".alert_word_status_text");
|
||||
return status_text;
|
||||
}
|
||||
|
||||
async function close_alert_words_status(page) {
|
||||
async function close_alert_words_status(page: Page): Promise<void> {
|
||||
const status_close_btn = ".close-alert-word-status";
|
||||
await page.click(status_close_btn);
|
||||
await page.waitForSelector(alert_word_status_selector, {hidden: true});
|
||||
}
|
||||
|
||||
async function test_and_close_alert_word_added_successfully_status(page, word) {
|
||||
async function test_and_close_alert_word_added_successfully_status(
|
||||
page: Page,
|
||||
word: string,
|
||||
): Promise<void> {
|
||||
const status_text = await get_alert_words_status_text(page);
|
||||
assert.strictEqual(status_text, `Alert word "${word}" added successfully!`);
|
||||
await close_alert_words_status(page);
|
||||
}
|
||||
|
||||
async function test_duplicate_alert_words_cannot_be_added(page, duplicate_word) {
|
||||
async function test_duplicate_alert_words_cannot_be_added(
|
||||
page: Page,
|
||||
duplicate_word: string,
|
||||
): Promise<void> {
|
||||
await add_alert_word(page, duplicate_word);
|
||||
const status_text = await get_alert_words_status_text(page);
|
||||
assert.strictEqual(status_text, "Alert word already exists!");
|
||||
await close_alert_words_status(page);
|
||||
}
|
||||
|
||||
async function delete_alert_word(page, word) {
|
||||
async function delete_alert_word(page: Page, word: string): Promise<void> {
|
||||
const delete_btn_selector = `.remove-alert-word[data-word="${CSS.escape(word)}"]`;
|
||||
await page.click(delete_btn_selector);
|
||||
await page.waitForSelector(delete_btn_selector, {hidden: true});
|
||||
}
|
||||
|
||||
async function test_alert_word_deletion(page, word) {
|
||||
async function test_alert_word_deletion(page: Page, word: string): Promise<void> {
|
||||
await delete_alert_word(page, word);
|
||||
const status_text = await get_alert_words_status_text(page);
|
||||
assert.strictEqual(status_text, "Alert word removed successfully!");
|
||||
await close_alert_words_status(page);
|
||||
}
|
||||
|
||||
async function test_alert_words_section(page) {
|
||||
async function test_alert_words_section(page: Page): Promise<void> {
|
||||
await page.click('[data-section="alert-words"]');
|
||||
const word = "puppeteer";
|
||||
await add_alert_word(page, word);
|
||||
|
@ -239,7 +245,7 @@ async function test_alert_words_section(page) {
|
|||
await test_alert_word_deletion(page, word);
|
||||
}
|
||||
|
||||
async function change_language(page, language_data_code) {
|
||||
async function change_language(page: Page, language_data_code: string): Promise<void> {
|
||||
await page.waitForSelector("#default_language", {visible: true});
|
||||
await page.click("#default_language");
|
||||
await page.waitForSelector("#default_language_modal", {visible: true});
|
||||
|
@ -247,19 +253,19 @@ async function change_language(page, language_data_code) {
|
|||
await page.click(language_selector);
|
||||
}
|
||||
|
||||
async function check_language_setting_status(page) {
|
||||
async function check_language_setting_status(page: Page): Promise<void> {
|
||||
const language_setting_status_selector = "#language-settings-status";
|
||||
await page.waitForSelector(language_setting_status_selector, {visible: true});
|
||||
const status_text = "Saved. Please reload for the change to take effect.";
|
||||
await page.waitForFunction(
|
||||
(selector, status) => $(selector).text() === status,
|
||||
(selector: string, status: string) => $(selector).text() === status,
|
||||
{},
|
||||
language_setting_status_selector,
|
||||
status_text,
|
||||
);
|
||||
}
|
||||
|
||||
async function assert_language_changed_to_chinese(page) {
|
||||
async function assert_language_changed_to_chinese(page: Page): Promise<void> {
|
||||
await page.waitForSelector("#default_language", {visible: true});
|
||||
const default_language = await common.get_text_from_selector(page, "#default_language");
|
||||
assert.strictEqual(
|
||||
|
@ -269,7 +275,7 @@ async function assert_language_changed_to_chinese(page) {
|
|||
);
|
||||
}
|
||||
|
||||
async function test_i18n_language_precedence(page) {
|
||||
async function test_i18n_language_precedence(page: Page): Promise<void> {
|
||||
const settings_url_for_german = "http://zulip.zulipdev.com:9981/de/#settings";
|
||||
await page.goto(settings_url_for_german);
|
||||
await page.waitForSelector("#settings-change-box", {visible: true});
|
||||
|
@ -277,7 +283,7 @@ async function test_i18n_language_precedence(page) {
|
|||
assert.strictEqual(page_language_code, "de");
|
||||
}
|
||||
|
||||
async function test_default_language_setting(page) {
|
||||
async function test_default_language_setting(page: Page): Promise<void> {
|
||||
const display_settings_section = '[data-section="display-settings"]';
|
||||
await page.click(display_settings_section);
|
||||
|
||||
|
@ -304,7 +310,7 @@ async function test_default_language_setting(page) {
|
|||
await page.waitForSelector("#default_language", {visible: true});
|
||||
}
|
||||
|
||||
async function test_notifications_section(page) {
|
||||
async function test_notifications_section(page: Page): Promise<void> {
|
||||
await page.click('[data-section="notifications"]');
|
||||
// At the beginning, "PMs, mentions, and alerts"(checkbox name=enable_sounds) audio will be on
|
||||
// and "Streams"(checkbox name=enable_stream_audible_notifications) audio will be off by default.
|
||||
|
@ -331,7 +337,7 @@ async function test_notifications_section(page) {
|
|||
*/
|
||||
}
|
||||
|
||||
async function settings_tests(page) {
|
||||
async function settings_tests(page: Page): Promise<void> {
|
||||
await common.log_in(page);
|
||||
await open_settings(page);
|
||||
await test_change_full_name(page);
|
|
@ -146,3 +146,7 @@ declare let user_events: any;
|
|||
declare let user_groups: any;
|
||||
declare let user_pill: any;
|
||||
declare let widgetize: any;
|
||||
|
||||
interface JQuery {
|
||||
expectOne(): JQuery;
|
||||
}
|
||||
|
|
|
@ -100,7 +100,9 @@ def find_js_test_files(test_dir: str, files: Iterable[str]) -> List[str]:
|
|||
test_files.append(os.path.abspath(file))
|
||||
|
||||
if not test_files:
|
||||
test_files = sorted(glob.glob(os.path.join(test_dir, "*.js")))
|
||||
test_files = sorted(
|
||||
glob.glob(os.path.join(test_dir, "*.ts")) + glob.glob(os.path.join(test_dir, "*.js"))
|
||||
)
|
||||
|
||||
return test_files
|
||||
|
||||
|
|
|
@ -61,7 +61,14 @@ def run_tests(files: Iterable[str], external_host: str) -> None:
|
|||
current_test_num = test_number
|
||||
for test_file in test_files[test_number:]:
|
||||
test_name = os.path.basename(test_file)
|
||||
cmd = ["node", "--unhandled-rejections=strict", test_file]
|
||||
cmd = [
|
||||
"node",
|
||||
"--unhandled-rejections=strict",
|
||||
os.path.join(ZULIP_PATH, "node_modules/.bin/ts-node"),
|
||||
"--script-mode",
|
||||
"--transpile-only",
|
||||
test_file,
|
||||
]
|
||||
print(
|
||||
"\n\n===================== {}\nRunning {}\n\n".format(
|
||||
test_name, " ".join(map(shlex.quote, cmd))
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
export const test_credentials: {
|
||||
default_user: {
|
||||
username: string;
|
||||
password: string;
|
||||
};
|
||||
};
|
Loading…
Reference in New Issue