mirror of
				https://github.com/zulip/zulip.git
				synced 2025-11-04 14:03:30 +00:00 
			
		
		
		
	puppeteer: Add compose tests and required functions in common.js.
Thanks to Priyank Patel for helping debug flakes.
This commit is contained in:
		@@ -10,6 +10,24 @@ class CommonUtils {
 | 
				
			|||||||
        this.browser = null;
 | 
					        this.browser = null;
 | 
				
			||||||
        this.screenshot_id = 0;
 | 
					        this.screenshot_id = 0;
 | 
				
			||||||
        this.realm_url = "http://zulip.zulipdev.com:9981/";
 | 
					        this.realm_url = "http://zulip.zulipdev.com:9981/";
 | 
				
			||||||
 | 
					        this.pm_recipient = {
 | 
				
			||||||
 | 
					            async set(page, recipient) {
 | 
				
			||||||
 | 
					                await page.type("#private_message_recipient", recipient);
 | 
				
			||||||
 | 
					                await page.keyboard.press("Enter");
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            async expect(page, expected) {
 | 
				
			||||||
 | 
					                const actual_recipients = await page.evaluate(() =>
 | 
				
			||||||
 | 
					                    compose_state.private_message_recipient(),
 | 
				
			||||||
 | 
					                );
 | 
				
			||||||
 | 
					                assert.equal(actual_recipients, expected);
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        this.fullname = {
 | 
				
			||||||
 | 
					            cordelia: "Cordelia Lear",
 | 
				
			||||||
 | 
					            othello: "Othello, the Moor of Venice",
 | 
				
			||||||
 | 
					            hamlet: "King Hamlet",
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async ensure_browser() {
 | 
					    async ensure_browser() {
 | 
				
			||||||
@@ -84,6 +102,43 @@ class CommonUtils {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    async check_form_contents(page, form_selector, params) {
 | 
				
			||||||
 | 
					        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),
 | 
				
			||||||
 | 
					                    expected_value,
 | 
				
			||||||
 | 
					                    "Form content is not as expected.",
 | 
				
			||||||
 | 
					                );
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                assert.equal(
 | 
				
			||||||
 | 
					                    await page.$eval(name_selector, (el) => el.value),
 | 
				
			||||||
 | 
					                    expected_value,
 | 
				
			||||||
 | 
					                    "Form content is not as expected.",
 | 
				
			||||||
 | 
					                );
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    async get_user_id_from_name(page, name) {
 | 
				
			||||||
 | 
					        if (this.fullname[name] !== undefined) {
 | 
				
			||||||
 | 
					            name = this.fullname[name];
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return await page.evaluate((name) => people.get_user_id_from_name(name), name);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    async get_internal_email_from_name(page, name) {
 | 
				
			||||||
 | 
					        if (this.fullname[name] !== undefined) {
 | 
				
			||||||
 | 
					            name = this.fullname[name];
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return await page.evaluate((fullname) => {
 | 
				
			||||||
 | 
					            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, credentials = null) {
 | 
				
			||||||
        console.log("Logging in");
 | 
					        console.log("Logging in");
 | 
				
			||||||
        await page.goto(this.realm_url + "login/");
 | 
					        await page.goto(this.realm_url + "login/");
 | 
				
			||||||
@@ -241,6 +296,8 @@ class CommonUtils {
 | 
				
			|||||||
        await page.evaluate(() => {
 | 
					        await page.evaluate(() => {
 | 
				
			||||||
            compose_actions.cancel();
 | 
					            compose_actions.cancel();
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
 | 
					        // Make sure the compose box is closed.
 | 
				
			||||||
 | 
					        await page.waitForSelector("#compose-textarea", {hidden: true});
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async send_multiple_messages(page, msgs) {
 | 
					    async send_multiple_messages(page, msgs) {
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										228
									
								
								frontend_tests/puppeteer_tests/03-compose.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										228
									
								
								frontend_tests/puppeteer_tests/03-compose.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,228 @@
 | 
				
			|||||||
 | 
					const assert = require("assert").strict;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const common = require("../puppeteer_lib/common");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					async function check_compose_form_empty(page) {
 | 
				
			||||||
 | 
					    await common.check_form_contents(page, "#send_message_form", {
 | 
				
			||||||
 | 
					        stream_message_recipient_stream: "",
 | 
				
			||||||
 | 
					        stream_message_recipient_topic: "",
 | 
				
			||||||
 | 
					        content: "",
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					async function close_compose_box(page) {
 | 
				
			||||||
 | 
					    await page.keyboard.press("Escape");
 | 
				
			||||||
 | 
					    await page.waitForSelector("#compose-textarea", {hidden: true});
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function get_message_xpath(text) {
 | 
				
			||||||
 | 
					    return `//p[text()='${text}']`;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function get_last_element(array) {
 | 
				
			||||||
 | 
					    return array.slice(-1)[0];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					async function test_send_messages(page) {
 | 
				
			||||||
 | 
					    await page.waitForSelector("#zhome .message_row", {visible: true});
 | 
				
			||||||
 | 
					    const initial_msgs_count = await page.evaluate(() => $("#zhome .message_row").length);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    await common.send_multiple_messages(page, [
 | 
				
			||||||
 | 
					        {stream: "Verona", topic: "Reply test", content: "Compose stream reply test"},
 | 
				
			||||||
 | 
					        {recipient: "cordelia@zulip.com", content: "Compose private message reply test"},
 | 
				
			||||||
 | 
					    ]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    assert.equal(
 | 
				
			||||||
 | 
					        await page.evaluate(() => $("#zhome .message_row").length),
 | 
				
			||||||
 | 
					        initial_msgs_count + 2,
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					async function test_stream_compose_keyboard_shortcut(page) {
 | 
				
			||||||
 | 
					    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) {
 | 
				
			||||||
 | 
					    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) {
 | 
				
			||||||
 | 
					    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) {
 | 
				
			||||||
 | 
					    const stream_message = get_last_element(
 | 
				
			||||||
 | 
					        await page.$x(get_message_xpath("Compose stream reply test")),
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    // we chose only the last element make sure we don't click on any duplicates.
 | 
				
			||||||
 | 
					    await stream_message.click();
 | 
				
			||||||
 | 
					    await common.check_form_contents(page, "#send_message_form", {
 | 
				
			||||||
 | 
					        stream_message_recipient_stream: "Verona",
 | 
				
			||||||
 | 
					        stream_message_recipient_topic: "Reply test",
 | 
				
			||||||
 | 
					        content: "",
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    await close_compose_box(page);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					async function test_reply_by_click_prepopulates_private_message_recipient(page) {
 | 
				
			||||||
 | 
					    const private_message = get_last_element(
 | 
				
			||||||
 | 
					        await page.$x(get_message_xpath("Compose private message reply test")),
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    await private_message.click();
 | 
				
			||||||
 | 
					    await page.waitForSelector("#private_message_recipient", {visible: true});
 | 
				
			||||||
 | 
					    await common.pm_recipient.expect(
 | 
				
			||||||
 | 
					        page,
 | 
				
			||||||
 | 
					        await common.get_internal_email_from_name(page, "cordelia"),
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    await close_compose_box(page);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					async function test_reply_with_r_shortcut(page) {
 | 
				
			||||||
 | 
					    // 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");
 | 
				
			||||||
 | 
					    await page.keyboard.press("KeyR");
 | 
				
			||||||
 | 
					    await common.check_form_contents(page, "#send_message_form", {
 | 
				
			||||||
 | 
					        stream_message_recipient_stream: "Verona",
 | 
				
			||||||
 | 
					        stream_message_recipient_topic: "Reply test",
 | 
				
			||||||
 | 
					        content: "",
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					async function test_open_close_compose_box(page) {
 | 
				
			||||||
 | 
					    await page.waitForSelector("#stream-message", {hidden: false});
 | 
				
			||||||
 | 
					    await close_compose_box(page);
 | 
				
			||||||
 | 
					    await page.waitForSelector("#stream-message", {hidden: true});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    await page.keyboard.press("KeyX");
 | 
				
			||||||
 | 
					    await page.waitForSelector("#private-message", {hidden: false});
 | 
				
			||||||
 | 
					    await close_compose_box(page);
 | 
				
			||||||
 | 
					    await page.waitForSelector("#private-message", {hidden: true});
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					async function test_narrow_to_private_messages_with_cordelia(page) {
 | 
				
			||||||
 | 
					    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(),
 | 
				
			||||||
 | 
					        you_and_cordelia_selector,
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    const cordelia_user_id = await common.get_user_id_from_name(page, "Cordelia Lear");
 | 
				
			||||||
 | 
					    const pm_list_selector = `li[data-user-ids-string="${cordelia_user_id}"].expanded_private_message.active-sub-filter`;
 | 
				
			||||||
 | 
					    await page.waitForSelector(pm_list_selector, {visible: true});
 | 
				
			||||||
 | 
					    await close_compose_box(page);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    await page.keyboard.press("KeyC");
 | 
				
			||||||
 | 
					    await page.waitForSelector("#compose", {visible: true});
 | 
				
			||||||
 | 
					    await page.waitForFunction(
 | 
				
			||||||
 | 
					        () => document.activeElement === $(".compose_table #stream_message_recipient_stream")[0],
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    await close_compose_box(page);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					async function test_send_multirecipient_pm_from_cordelia_pm_narrow(page) {
 | 
				
			||||||
 | 
					    const recipients = ["cordelia@zulip.com", "othello@zulip.com"];
 | 
				
			||||||
 | 
					    const multiple_recipients_pm = "A huddle to check spaces";
 | 
				
			||||||
 | 
					    const pm_selector = `.messagebox:contains('${multiple_recipients_pm}')`;
 | 
				
			||||||
 | 
					    await common.send_message(page, "private", {
 | 
				
			||||||
 | 
					        recipient: recipients.join(", "),
 | 
				
			||||||
 | 
					        outside_view: true,
 | 
				
			||||||
 | 
					        content: multiple_recipients_pm,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Go back to all messages view and make sure all messages are loaded.
 | 
				
			||||||
 | 
					    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) => {
 | 
				
			||||||
 | 
					        $(selector).slice(-1)[0].click();
 | 
				
			||||||
 | 
					    }, pm_selector);
 | 
				
			||||||
 | 
					    await page.waitForSelector("#compose-textarea", {visible: true});
 | 
				
			||||||
 | 
					    const recipient_internal_emails = [
 | 
				
			||||||
 | 
					        await common.get_internal_email_from_name(page, "othello"),
 | 
				
			||||||
 | 
					        await common.get_internal_email_from_name(page, "cordelia"),
 | 
				
			||||||
 | 
					    ].join(",");
 | 
				
			||||||
 | 
					    await common.pm_recipient.expect(page, recipient_internal_emails);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const markdown_preview_button = "#markdown_preview";
 | 
				
			||||||
 | 
					const markdown_preview_hide_button = "#undo_markdown_preview";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					async function test_markdown_preview_buttons_visibility(page) {
 | 
				
			||||||
 | 
					    await page.waitForSelector(markdown_preview_button, {visible: true});
 | 
				
			||||||
 | 
					    await page.waitForSelector(markdown_preview_hide_button, {visible: false});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // verify if markdowm preview button works.
 | 
				
			||||||
 | 
					    await page.click(markdown_preview_button);
 | 
				
			||||||
 | 
					    await page.waitForSelector(markdown_preview_button, {visible: false});
 | 
				
			||||||
 | 
					    await page.waitForSelector(markdown_preview_hide_button, {visible: true});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // verify if write button works.
 | 
				
			||||||
 | 
					    await page.click(markdown_preview_hide_button);
 | 
				
			||||||
 | 
					    await page.waitForSelector(markdown_preview_button, {visible: true});
 | 
				
			||||||
 | 
					    await page.waitForSelector(markdown_preview_hide_button, {visible: false});
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					async function test_markdown_preview_without_any_content(page) {
 | 
				
			||||||
 | 
					    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),
 | 
				
			||||||
 | 
					        "Nothing to preview",
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    await page.click("#undo_markdown_preview");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					async function test_markdown_rendering(page) {
 | 
				
			||||||
 | 
					    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 common.fill_form(page, 'form[action^="/json/messages"]', {
 | 
				
			||||||
 | 
					        content: "**Markdown Preview** >> Test for markdown preview",
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    await page.click("#markdown_preview");
 | 
				
			||||||
 | 
					    await page.waitForSelector("#preview_content", {visible: true});
 | 
				
			||||||
 | 
					    const expected_markdown_html =
 | 
				
			||||||
 | 
					        "<p><strong>Markdown Preview</strong> >> Test for markdown preview</p>";
 | 
				
			||||||
 | 
					    await page.waitForFunction(() => $("#preview_content").html() !== "");
 | 
				
			||||||
 | 
					    markdown_preview_element = await page.$("#preview_content");
 | 
				
			||||||
 | 
					    assert.equal(
 | 
				
			||||||
 | 
					        await page.evaluate((element) => element.innerHTML, markdown_preview_element),
 | 
				
			||||||
 | 
					        expected_markdown_html,
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					async function test_markdown_preview(page) {
 | 
				
			||||||
 | 
					    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) {
 | 
				
			||||||
 | 
					    await common.log_in(page);
 | 
				
			||||||
 | 
					    await test_send_messages(page);
 | 
				
			||||||
 | 
					    await test_keyboard_shortcuts(page);
 | 
				
			||||||
 | 
					    await test_reply_by_click_prepopulates_stream_topic_names(page);
 | 
				
			||||||
 | 
					    await test_reply_by_click_prepopulates_private_message_recipient(page);
 | 
				
			||||||
 | 
					    await test_reply_with_r_shortcut(page);
 | 
				
			||||||
 | 
					    await test_open_close_compose_box(page);
 | 
				
			||||||
 | 
					    await test_narrow_to_private_messages_with_cordelia(page);
 | 
				
			||||||
 | 
					    await test_send_multirecipient_pm_from_cordelia_pm_narrow(page);
 | 
				
			||||||
 | 
					    await test_markdown_preview(page);
 | 
				
			||||||
 | 
					    await common.log_out(page);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					common.run_test(compose_tests);
 | 
				
			||||||
		Reference in New Issue
	
	Block a user