mirror of https://github.com/zulip/zulip.git
casper: Remove few traces of casper.
Now that all casper tests have been migrated to puppeteer, there's no need for having casper related things. Removed the casperjs package and removed/replaced casper in few places with puppeteer. Only removed few of them which I'm confident about. Also didn't make any changes in docs as it would be easier to remove them while adding puppeteer docs.
This commit is contained in:
parent
38eac64d91
commit
2d22d88700
|
@ -211,16 +211,10 @@ jobs:
|
||||||
# runs the frontend tests.
|
# runs the frontend tests.
|
||||||
- *upload_coverage_report
|
- *upload_coverage_report
|
||||||
|
|
||||||
- store_artifacts:
|
|
||||||
path: ./var/casper/
|
|
||||||
destination: casper
|
|
||||||
|
|
||||||
- store_artifacts:
|
- store_artifacts:
|
||||||
path: ./var/puppeteer/
|
path: ./var/puppeteer/
|
||||||
destination: puppeteer
|
destination: puppeteer
|
||||||
|
|
||||||
- store_test_results:
|
|
||||||
path: ./var/xunit-test-results/casper/
|
|
||||||
- *notify_failure_status
|
- *notify_failure_status
|
||||||
|
|
||||||
"focal-backend":
|
"focal-backend":
|
||||||
|
|
|
@ -343,7 +343,6 @@
|
||||||
"files": ["frontend_tests/**"],
|
"files": ["frontend_tests/**"],
|
||||||
"globals": {
|
"globals": {
|
||||||
"assert": false,
|
"assert": false,
|
||||||
"casper": false,
|
|
||||||
"document": false,
|
"document": false,
|
||||||
"set_global": false,
|
"set_global": false,
|
||||||
"window": false,
|
"window": false,
|
||||||
|
@ -355,11 +354,7 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"files": [
|
"files": ["tools/debug-require.js"],
|
||||||
"frontend_tests/casper_lib/**",
|
|
||||||
"frontend_tests/casper_tests/**",
|
|
||||||
"tools/debug-require.js"
|
|
||||||
],
|
|
||||||
"env": {
|
"env": {
|
||||||
"browser": true,
|
"browser": true,
|
||||||
"es2020": false
|
"es2020": false
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
/server.log
|
|
||||||
/test_credentials.js
|
|
|
@ -1,512 +0,0 @@
|
||||||
"use strict";
|
|
||||||
|
|
||||||
var util = require("util");
|
|
||||||
|
|
||||||
var test_credentials = require("../../var/casper/test_credentials.js").test_credentials;
|
|
||||||
|
|
||||||
casper.options.clientScripts.push("frontend_tests/casper_lib/polyfill.js");
|
|
||||||
|
|
||||||
function timestamp() {
|
|
||||||
return new Date().getTime();
|
|
||||||
}
|
|
||||||
|
|
||||||
// The timestamp of the last message send or get_events result.
|
|
||||||
var last_send_or_update = -1;
|
|
||||||
|
|
||||||
function log_in() {
|
|
||||||
var credentials = test_credentials.default_user;
|
|
||||||
|
|
||||||
casper.test.info("Logging in");
|
|
||||||
casper.fill(
|
|
||||||
'form[action^="/accounts/login/"]',
|
|
||||||
{
|
|
||||||
username: credentials.username,
|
|
||||||
password: credentials.password,
|
|
||||||
},
|
|
||||||
true /* submit form */
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
exports.init_viewport = function () {
|
|
||||||
casper.options.viewportSize = {width: 1280, height: 1024};
|
|
||||||
};
|
|
||||||
|
|
||||||
// This function should always be enclosed within a then() otherwise
|
|
||||||
// it might not exist on casper object.
|
|
||||||
exports.wait_for_text = function (selector, text, then, onTimeout, timeout) {
|
|
||||||
casper.waitForSelector(
|
|
||||||
selector,
|
|
||||||
function _then() {
|
|
||||||
casper.waitFor(
|
|
||||||
function _check() {
|
|
||||||
var content = casper.fetchText(selector);
|
|
||||||
if (util.isRegExp(text)) {
|
|
||||||
return text.test(content);
|
|
||||||
}
|
|
||||||
return content.indexOf(text) !== -1;
|
|
||||||
},
|
|
||||||
then,
|
|
||||||
onTimeout,
|
|
||||||
timeout
|
|
||||||
);
|
|
||||||
},
|
|
||||||
onTimeout,
|
|
||||||
timeout
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.initialize_casper = function () {
|
|
||||||
if (casper.zulip_initialized !== undefined) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
casper.zulip_initialized = true;
|
|
||||||
// These initialization steps will fail if they run before
|
|
||||||
// casper.start has been called.
|
|
||||||
|
|
||||||
// Fail if we get a JavaScript error in the page's context.
|
|
||||||
// Based on the example at https://phantomjs.org/release-1.5.html
|
|
||||||
//
|
|
||||||
// casper.on('error') doesn't work (it never gets called) so we
|
|
||||||
// set this at the PhantomJS level.
|
|
||||||
casper.page.onError = function (msg, trace) {
|
|
||||||
casper.test.error(msg);
|
|
||||||
casper.echo("Traceback:");
|
|
||||||
trace.forEach(function (item) {
|
|
||||||
casper.echo(" " + item.file + ":" + item.line);
|
|
||||||
});
|
|
||||||
casper.exit(1);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Capture screens from all failures
|
|
||||||
var casper_failure_count = 1;
|
|
||||||
casper.test.on("fail", function failure() {
|
|
||||||
if (casper_failure_count <= 10) {
|
|
||||||
casper.capture("var/casper/casper-failure" + casper_failure_count + ".png");
|
|
||||||
casper_failure_count += 1;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Update last_send_or_update whenever get_events returns.
|
|
||||||
casper.on("resource.received", function (resource) {
|
|
||||||
if (/\/json\/get_events/.test(resource.url)) {
|
|
||||||
last_send_or_update = timestamp();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
casper.on("load.finished", function () {
|
|
||||||
casper.test.info("page load finished");
|
|
||||||
});
|
|
||||||
|
|
||||||
casper.evaluate(function () {
|
|
||||||
window.localStorage.clear();
|
|
||||||
});
|
|
||||||
|
|
||||||
// This captures console messages from the app.
|
|
||||||
casper.on("remote.message", function (msg) {
|
|
||||||
casper.echo("app console: " + msg);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.start_and_log_in = function () {
|
|
||||||
var log_in_url = "http://zulip.zulipdev.com:9981/accounts/login/";
|
|
||||||
exports.init_viewport();
|
|
||||||
casper.start(log_in_url, function () {
|
|
||||||
exports.initialize_casper();
|
|
||||||
log_in();
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.then_click = function (selector) {
|
|
||||||
casper.then(function () {
|
|
||||||
casper.waitUntilVisible(selector, function () {
|
|
||||||
casper.click(selector);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.then_log_in = function () {
|
|
||||||
casper.then(function () {
|
|
||||||
log_in();
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.then_log_out = function () {
|
|
||||||
var menu_selector = "#settings-dropdown";
|
|
||||||
var logout_selector = 'a[href="#logout"]';
|
|
||||||
|
|
||||||
casper.waitUntilVisible(menu_selector, function () {
|
|
||||||
casper.click(menu_selector);
|
|
||||||
|
|
||||||
casper.waitUntilVisible(logout_selector, function () {
|
|
||||||
casper.test.info("Logging out");
|
|
||||||
casper.click(logout_selector);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
casper.waitUntilVisible(".login-page-container", function () {
|
|
||||||
casper.test.assertUrlMatch(/accounts\/login\/$/);
|
|
||||||
casper.test.info("Logged out");
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// Put the specified string into the field_selector, then
|
|
||||||
// select the menu item matching item by typing str.
|
|
||||||
exports.select_item_via_typeahead = function (field_selector, str, item) {
|
|
||||||
casper.then(function () {
|
|
||||||
casper.test.info("Looking in " + field_selector + " to select " + str + ", " + item);
|
|
||||||
|
|
||||||
casper.evaluate(
|
|
||||||
function (field_selector, str, item) {
|
|
||||||
// Set the value and then send a bogus keyup event to trigger
|
|
||||||
// the typeahead.
|
|
||||||
$(field_selector)
|
|
||||||
.trigger("focus")
|
|
||||||
.val(str)
|
|
||||||
.trigger($.Event("keyup", {which: 0}));
|
|
||||||
|
|
||||||
// You might think these steps should be split by casper.then,
|
|
||||||
// but apparently that's enough to make the typeahead close (??),
|
|
||||||
// but not the first time.
|
|
||||||
|
|
||||||
// Trigger the typeahead.
|
|
||||||
// Reaching into the guts of Bootstrap Typeahead like this is not
|
|
||||||
// great, but I found it very hard to do it any other way.
|
|
||||||
|
|
||||||
var tah = $(field_selector).data().typeahead;
|
|
||||||
tah.mouseenter({
|
|
||||||
currentTarget: $('.typeahead:visible li:contains("' + item + '")')[0],
|
|
||||||
});
|
|
||||||
tah.select();
|
|
||||||
},
|
|
||||||
{field_selector: field_selector, str: str, item: item}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.check_form = function (form_selector, expected, test_name) {
|
|
||||||
var values = casper.getFormValues(form_selector);
|
|
||||||
var k;
|
|
||||||
for (k in expected) {
|
|
||||||
if (Object.prototype.hasOwnProperty.call(expected, k)) {
|
|
||||||
casper.test.assertEqual(
|
|
||||||
values[k],
|
|
||||||
expected[k],
|
|
||||||
test_name ? test_name + ": " + k : undefined
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.wait_for_message_fully_processed = function (content) {
|
|
||||||
casper.waitFor(function () {
|
|
||||||
return casper.evaluate(
|
|
||||||
function (content) {
|
|
||||||
/*
|
|
||||||
The tricky part about making sure that
|
|
||||||
a message has actually been fully processed
|
|
||||||
is that we'll "locally echo" the message
|
|
||||||
first on the client. Until the server
|
|
||||||
actually acks the message, the message will
|
|
||||||
have a temporary id and will not have all
|
|
||||||
the normal message controls.
|
|
||||||
|
|
||||||
For the Casper tests, we want to avoid all
|
|
||||||
the edge cases with locally echoed messages.
|
|
||||||
|
|
||||||
In order to make sure a message is processed,
|
|
||||||
we use internals to determine the following:
|
|
||||||
- has message_list even been updated with
|
|
||||||
the message with out content?
|
|
||||||
- has the locally_echoed flag been cleared?
|
|
||||||
|
|
||||||
But for the final steps we look at the
|
|
||||||
actual DOM (via JQuery):
|
|
||||||
- is it visible?
|
|
||||||
- does it look to have been
|
|
||||||
re-rendered based on server info?
|
|
||||||
*/
|
|
||||||
var last_msg = current_msg_list.last();
|
|
||||||
|
|
||||||
if (last_msg.raw_content !== content) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (last_msg.locally_echoed) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
var row = rows.last_visible();
|
|
||||||
|
|
||||||
if (rows.id(row) !== last_msg.id) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Make sure the message is completely
|
|
||||||
re-rendered from its original "local echo"
|
|
||||||
version by looking for the star icon. We
|
|
||||||
don't add the star icon until the server
|
|
||||||
responds.
|
|
||||||
*/
|
|
||||||
return row.find(".star").length === 1;
|
|
||||||
},
|
|
||||||
{content: content}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.turn_off_press_enter_to_send = function () {
|
|
||||||
var enter_send_selector = "#enter_sends";
|
|
||||||
casper.waitForSelector(enter_send_selector);
|
|
||||||
|
|
||||||
var is_checked = casper.evaluate(function (enter_send_selector) {
|
|
||||||
return document.querySelector(enter_send_selector).checked;
|
|
||||||
}, enter_send_selector);
|
|
||||||
|
|
||||||
if (is_checked) {
|
|
||||||
casper.click(enter_send_selector);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.pm_recipient = {
|
|
||||||
set: function (recip) {
|
|
||||||
casper.evaluate(
|
|
||||||
function (recipient) {
|
|
||||||
$("#private_message_recipient")
|
|
||||||
.text(recipient)
|
|
||||||
.trigger({type: "keydown", keyCode: 13});
|
|
||||||
},
|
|
||||||
{recipient: recip}
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
expect: function (expected_value) {
|
|
||||||
var displayed_recipients = casper.evaluate(function () {
|
|
||||||
return compose_state.private_message_recipient();
|
|
||||||
});
|
|
||||||
casper.test.assertEquals(displayed_recipients, expected_value);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
// Wait for any previous send to finish, then send a message.
|
|
||||||
exports.then_send_message = function (type, params) {
|
|
||||||
// If a message is outside the view, we will skip
|
|
||||||
// validation later.
|
|
||||||
var outside_view = params.outside_view;
|
|
||||||
delete params.outside_view;
|
|
||||||
|
|
||||||
casper.then(function () {
|
|
||||||
casper.waitForSelector("#compose-send-button:enabled");
|
|
||||||
casper.waitForSelector("#compose-textarea");
|
|
||||||
});
|
|
||||||
|
|
||||||
casper.then(function () {
|
|
||||||
if (type === "stream") {
|
|
||||||
casper.page.sendEvent("keypress", "c");
|
|
||||||
} else if (type === "private") {
|
|
||||||
casper.page.sendEvent("keypress", "x");
|
|
||||||
} else {
|
|
||||||
casper.test.assertTrue(false, "send_message got valid message type");
|
|
||||||
}
|
|
||||||
|
|
||||||
exports.pm_recipient.set(params.recipient);
|
|
||||||
delete params.recipient;
|
|
||||||
|
|
||||||
if (params.stream) {
|
|
||||||
params.stream_message_recipient_stream = params.stream;
|
|
||||||
delete params.stream;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (params.subject) {
|
|
||||||
params.stream_message_recipient_topic = params.subject;
|
|
||||||
delete params.subject;
|
|
||||||
}
|
|
||||||
|
|
||||||
casper.fill('form[action^="/json/messages"]', params);
|
|
||||||
|
|
||||||
exports.turn_off_press_enter_to_send();
|
|
||||||
|
|
||||||
casper.then(function () {
|
|
||||||
casper.click("#compose-send-button");
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
casper.then(function () {
|
|
||||||
casper.waitFor(function emptyComposeBox() {
|
|
||||||
return casper.getFormValues('form[action^="/json/messages"]').content === "";
|
|
||||||
});
|
|
||||||
if (!outside_view) {
|
|
||||||
exports.wait_for_message_fully_processed(params.content);
|
|
||||||
}
|
|
||||||
casper.evaluate(function () {
|
|
||||||
compose_actions.cancel();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
casper.then(function () {
|
|
||||||
last_send_or_update = timestamp();
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// Get message headings (recipient rows) and bodies out of the DOM.
|
|
||||||
// casper.evaluate plays weird tricks with a closure, evaluating
|
|
||||||
// it in the web page's context. Passing arguments from the test
|
|
||||||
// script's context is awkward (c.f. the various appearances of
|
|
||||||
// 'table' here).
|
|
||||||
exports.get_rendered_messages = function (table) {
|
|
||||||
return casper.evaluate(
|
|
||||||
function (table) {
|
|
||||||
var tbl = $("#" + table);
|
|
||||||
return {
|
|
||||||
headings: $.map(tbl.find(".recipient_row .message-header-contents"), function (
|
|
||||||
elem
|
|
||||||
) {
|
|
||||||
var $clone = $(elem).clone(true);
|
|
||||||
$clone.find(".recipient_row_date").remove();
|
|
||||||
|
|
||||||
return $clone.text().trim().replace(/\s+/g, " ");
|
|
||||||
}),
|
|
||||||
|
|
||||||
bodies: $.map(tbl.find(".message_content"), function (elem) {
|
|
||||||
return elem.innerHTML;
|
|
||||||
}),
|
|
||||||
};
|
|
||||||
},
|
|
||||||
{
|
|
||||||
table: table,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.get_form_field_value = function (selector) {
|
|
||||||
return casper.evaluate(function (selector) {
|
|
||||||
return $(selector).val();
|
|
||||||
}, selector);
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.get_user_id = function (email) {
|
|
||||||
return casper.evaluate(
|
|
||||||
function (email) {
|
|
||||||
return people.get_user_id(email);
|
|
||||||
},
|
|
||||||
{
|
|
||||||
email: email,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.get_stream_id = function (stream_name) {
|
|
||||||
return casper.evaluate(
|
|
||||||
function (stream_name) {
|
|
||||||
return stream_data.get_stream_id(stream_name);
|
|
||||||
},
|
|
||||||
{
|
|
||||||
stream_name: stream_name,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Inject key presses by running some jQuery code in page context.
|
|
||||||
// PhantomJS and CasperJS don't provide a clean way to insert key
|
|
||||||
// presses by code, only strings of printable characters.
|
|
||||||
exports.keypress = function (code) {
|
|
||||||
casper.evaluate(
|
|
||||||
function (code) {
|
|
||||||
$("body").trigger($.Event("keydown", {which: code}));
|
|
||||||
},
|
|
||||||
{
|
|
||||||
code: code,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.then_send_many = function (msgs) {
|
|
||||||
msgs.forEach(function (msg) {
|
|
||||||
exports.then_send_message(msg.stream !== undefined ? "stream" : "private", msg);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// Wait to receive queued messages.
|
|
||||||
exports.wait_for_receive = function (step) {
|
|
||||||
// Wait until the last send or get_events result was more than 1000 ms ago.
|
|
||||||
casper.waitFor(function () {
|
|
||||||
return timestamp() - last_send_or_update > 1000;
|
|
||||||
}, step);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Wait until the loading spinner goes away (helpful just after logging in).
|
|
||||||
exports.wait_for_load = function (step) {
|
|
||||||
casper.waitWhileVisible("#page_loading_indicator", step);
|
|
||||||
};
|
|
||||||
|
|
||||||
// innerText sometimes gives us non-breaking space characters, and occasionally
|
|
||||||
// a different number of spaces than we expect.
|
|
||||||
exports.normalize_spaces = function (str) {
|
|
||||||
return str.replace(/\s+/g, " ");
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.ltrim = function (str) {
|
|
||||||
return str.replace(/^\s+/g, "");
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.rtrim = function (str) {
|
|
||||||
return str.replace(/\s+$/g, "");
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.trim = function (str) {
|
|
||||||
return exports.rtrim(exports.ltrim(str));
|
|
||||||
};
|
|
||||||
|
|
||||||
// Call get_rendered_messages and then check that the last few headings and
|
|
||||||
// bodies match the specified arrays.
|
|
||||||
exports.expected_messages = function (table, headings, bodies) {
|
|
||||||
casper.test.assertVisible("#" + table, table + " is visible");
|
|
||||||
|
|
||||||
var msg = exports.get_rendered_messages(table);
|
|
||||||
|
|
||||||
casper.test.assertEquals(
|
|
||||||
msg.headings.slice(-headings.length),
|
|
||||||
headings.map(exports.trim),
|
|
||||||
"Got expected message headings"
|
|
||||||
);
|
|
||||||
|
|
||||||
casper.test.assertEquals(
|
|
||||||
msg.bodies.slice(-bodies.length),
|
|
||||||
bodies,
|
|
||||||
"Got expected message bodies"
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.un_narrow = function () {
|
|
||||||
casper.test.info("Un-narrowing");
|
|
||||||
if (casper.visible(".message_comp")) {
|
|
||||||
// close the compose box
|
|
||||||
common.keypress(27); // Esc
|
|
||||||
}
|
|
||||||
common.keypress(27); // Esc
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.manage_organization = function () {
|
|
||||||
casper.then(function () {
|
|
||||||
var menu_selector = "#settings-dropdown";
|
|
||||||
casper.waitUntilVisible(menu_selector, function () {
|
|
||||||
casper.click(menu_selector);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
casper.then(function () {
|
|
||||||
casper.test.info("Organization page");
|
|
||||||
casper.click('a[href^="#organization"]');
|
|
||||||
});
|
|
||||||
|
|
||||||
casper.waitForSelector("#settings_overlay_container.show", function () {
|
|
||||||
casper.test.info("Organization page is active");
|
|
||||||
casper.test.assertUrlMatch(
|
|
||||||
/^http:\/\/[^/]+\/#organization/,
|
|
||||||
"URL suggests we are on organization page"
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
casper.then(function () {
|
|
||||||
casper.click("li[data-section='organization-settings']");
|
|
||||||
});
|
|
||||||
};
|
|
|
@ -1,14 +0,0 @@
|
||||||
"use strict";
|
|
||||||
|
|
||||||
/* eslint-env browser */
|
|
||||||
|
|
||||||
// PhantomJS doesn’t support new DOMParser().parseFromString(…, "text/html").
|
|
||||||
var real_parseFromString = DOMParser.prototype.parseFromString;
|
|
||||||
DOMParser.prototype.parseFromString = function (string, type) {
|
|
||||||
if (type === "text/html") {
|
|
||||||
var doc = document.implementation.createHTMLDocument("");
|
|
||||||
doc.documentElement.innerHTML = string;
|
|
||||||
return doc;
|
|
||||||
}
|
|
||||||
return real_parseFromString.apply(this, arguments);
|
|
||||||
};
|
|
|
@ -5,7 +5,7 @@ const path = require("path");
|
||||||
|
|
||||||
const puppeteer = require("puppeteer");
|
const puppeteer = require("puppeteer");
|
||||||
|
|
||||||
const test_credentials = require("../../var/casper/test_credentials.js").test_credentials;
|
const test_credentials = require("../../var/puppeteer/test_credentials.js").test_credentials;
|
||||||
|
|
||||||
class CommonUtils {
|
class CommonUtils {
|
||||||
constructor() {
|
constructor() {
|
||||||
|
@ -238,7 +238,7 @@ class CommonUtils {
|
||||||
actually acks the message, the message will
|
actually acks the message, the message will
|
||||||
have a temporary id and will not have all
|
have a temporary id and will not have all
|
||||||
the normal message controls.
|
the normal message controls.
|
||||||
For the Casper tests, we want to avoid all
|
For the Puppeteer tests, we want to avoid all
|
||||||
the edge cases with locally echoed messages.
|
the edge cases with locally echoed messages.
|
||||||
In order to make sure a message is processed,
|
In order to make sure a message is processed,
|
||||||
we use internals to determine the following:
|
we use internals to determine the following:
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const test_credentials = require("../../var/casper/test_credentials.js").test_credentials;
|
const test_credentials = require("../../var/puppeteer/test_credentials.js").test_credentials;
|
||||||
const common = require("../puppeteer_lib/common");
|
const common = require("../puppeteer_lib/common");
|
||||||
|
|
||||||
async function login_tests(page) {
|
async function login_tests(page) {
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
const assert = require("assert").strict;
|
const assert = require("assert").strict;
|
||||||
|
|
||||||
const test_credentials = require("../../var/casper/test_credentials.js").test_credentials;
|
const test_credentials = require("../../var/puppeteer/test_credentials.js").test_credentials;
|
||||||
const common = require("../puppeteer_lib/common");
|
const common = require("../puppeteer_lib/common");
|
||||||
|
|
||||||
const OUTGOING_WEBHOOK_BOT_TYPE = "3";
|
const OUTGOING_WEBHOOK_BOT_TYPE = "3";
|
||||||
|
|
|
@ -1,178 +0,0 @@
|
||||||
#!/usr/bin/env python3
|
|
||||||
import argparse
|
|
||||||
import glob
|
|
||||||
import os
|
|
||||||
import shlex
|
|
||||||
import subprocess
|
|
||||||
import sys
|
|
||||||
|
|
||||||
#
|
|
||||||
# In order to use remote casperjs debugging, pass the --remote-debug flag
|
|
||||||
# This will start a remote debugging session listening on port 7777
|
|
||||||
#
|
|
||||||
# See https://zulip.readthedocs.io/en/latest/testing/testing-with-casper.html
|
|
||||||
# for more information on how to use remote debugging
|
|
||||||
#
|
|
||||||
|
|
||||||
ZULIP_PATH = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|
||||||
|
|
||||||
os.environ["CASPER_TESTS"] = "1"
|
|
||||||
os.environ["PHANTOMJS_EXECUTABLE"] = os.path.join(ZULIP_PATH, "node_modules/.bin/phantomjs")
|
|
||||||
os.environ.pop("http_proxy", "")
|
|
||||||
os.environ.pop("https_proxy", "")
|
|
||||||
|
|
||||||
usage = """
|
|
||||||
|
|
||||||
test-js-with-casper # Run all test files
|
|
||||||
test-js-with-casper 09-navigation.js # Run a single test file
|
|
||||||
test-js-with-casper 09 # Run a single test file 09-navigation.js
|
|
||||||
test-js-with-casper 01-login.js 03-narrow.js # Run a few test files
|
|
||||||
test-js-with-casper 01 03 # Run a few test files, 01-login.js and 03-narrow.js here
|
|
||||||
|
|
||||||
Using loops:
|
|
||||||
|
|
||||||
test-js-with-capser --loop 5 07 # run 5 loops of test 07
|
|
||||||
---
|
|
||||||
"""
|
|
||||||
parser = argparse.ArgumentParser(usage=usage)
|
|
||||||
|
|
||||||
parser.add_argument('--skip-flaky-tests', dest='skip_flaky',
|
|
||||||
action="store_true",
|
|
||||||
default=False, help='Skip flaky tests')
|
|
||||||
parser.add_argument('--loop', dest='loop', nargs=1,
|
|
||||||
action="store", type=int,
|
|
||||||
default=None, help='Run tests in a loop.')
|
|
||||||
parser.add_argument('--force', dest='force',
|
|
||||||
action="store_true",
|
|
||||||
default=False, help='Run tests despite possible problems.')
|
|
||||||
parser.add_argument('--verbose',
|
|
||||||
help='Whether or not to enable verbose mode',
|
|
||||||
action="store_true",
|
|
||||||
default=False)
|
|
||||||
parser.add_argument('--remote-debug',
|
|
||||||
help='Whether or not to enable remote debugging on port 7777',
|
|
||||||
action="store_true",
|
|
||||||
default=False)
|
|
||||||
parser.add_argument('--xunit-export', dest='xunit_export',
|
|
||||||
action="store_true",
|
|
||||||
default=False, help='Export the results of the test suite to an XUnit XML file,')
|
|
||||||
parser.add_argument('tests', nargs=argparse.REMAINDER,
|
|
||||||
help='Specific tests to run; by default, runs all tests')
|
|
||||||
options = parser.parse_args()
|
|
||||||
|
|
||||||
sys.path.insert(0, ZULIP_PATH)
|
|
||||||
|
|
||||||
# check for the venv
|
|
||||||
from tools.lib import sanity_check
|
|
||||||
|
|
||||||
sanity_check.check_venv(__file__)
|
|
||||||
|
|
||||||
from typing import Iterable, List
|
|
||||||
|
|
||||||
from tools.lib.test_script import assert_provisioning_status_ok, find_js_test_files
|
|
||||||
from tools.lib.test_server import test_server_running
|
|
||||||
|
|
||||||
assert_provisioning_status_ok(options.force)
|
|
||||||
|
|
||||||
os.chdir(ZULIP_PATH)
|
|
||||||
|
|
||||||
subprocess.check_call(['node', 'node_modules/phantomjs-prebuilt/install.js'])
|
|
||||||
|
|
||||||
os.makedirs('var/casper', exist_ok=True)
|
|
||||||
|
|
||||||
for f in glob.glob('var/casper/casper-failure*.png'):
|
|
||||||
os.remove(f)
|
|
||||||
|
|
||||||
def reset_database() -> None:
|
|
||||||
from zerver.lib.test_helpers import reset_emails_in_zulip_realm
|
|
||||||
reset_emails_in_zulip_realm()
|
|
||||||
|
|
||||||
def run_tests(files: Iterable[str], external_host: str) -> None:
|
|
||||||
test_dir = os.path.join(ZULIP_PATH, 'frontend_tests/casper_tests')
|
|
||||||
test_files = find_js_test_files(test_dir, files)
|
|
||||||
|
|
||||||
# 10-admin.js is too flaky!
|
|
||||||
if options.skip_flaky:
|
|
||||||
test_files = [fn for fn in test_files if '10-admin' not in fn]
|
|
||||||
|
|
||||||
if options.loop:
|
|
||||||
loop_cnt = options.loop[0]
|
|
||||||
print('\n\nWe will use loop mode for these tests:\n')
|
|
||||||
for test_file in test_files:
|
|
||||||
print(' ' + os.path.basename(test_file))
|
|
||||||
print(f'\nnumber of loops: {loop_cnt}\n')
|
|
||||||
print()
|
|
||||||
else:
|
|
||||||
loop_cnt = None
|
|
||||||
|
|
||||||
remote_debug: List[str] = []
|
|
||||||
if options.remote_debug:
|
|
||||||
remote_debug = ["--remote-debugger-port=7777", "--remote-debugger-autorun=yes"]
|
|
||||||
|
|
||||||
verbose: List[str] = []
|
|
||||||
if options.verbose:
|
|
||||||
verbose = ["--verbose", "--log-level=debug"]
|
|
||||||
|
|
||||||
xunit_export: List[str] = []
|
|
||||||
if options.xunit_export:
|
|
||||||
xunit_export = ["--xunit=var/xunit-test-results/casper/result.xml"]
|
|
||||||
|
|
||||||
def run_tests() -> int:
|
|
||||||
ret = 1
|
|
||||||
for test_file in test_files:
|
|
||||||
test_name = os.path.basename(test_file)
|
|
||||||
cmd = ["node_modules/.bin/casperjs"] + remote_debug + verbose + xunit_export + ["test", test_file]
|
|
||||||
print("\n\n===================== {}\nRunning {}\n\n".format(test_name, " ".join(map(shlex.quote, cmd))), flush=True)
|
|
||||||
ret = subprocess.call(cmd)
|
|
||||||
if ret != 0:
|
|
||||||
return ret
|
|
||||||
return 0
|
|
||||||
|
|
||||||
def run_loops(loop_cnt: int) -> None:
|
|
||||||
while True:
|
|
||||||
for trial in range(1, loop_cnt + 1):
|
|
||||||
print(f'\n\n\nSTARTING TRIAL {trial} / {loop_cnt}\n')
|
|
||||||
ret = run_tests()
|
|
||||||
if ret == 0:
|
|
||||||
print(f'`\n\nSUCCESS! trial #{trial}\n\n')
|
|
||||||
else:
|
|
||||||
print(f'\n\nFAIL! trial #{trial}\n')
|
|
||||||
break
|
|
||||||
|
|
||||||
while True:
|
|
||||||
response = input('Press "q" to quit or enter number of loops: ')
|
|
||||||
if response == 'q':
|
|
||||||
return
|
|
||||||
try:
|
|
||||||
loop_cnt = int(response)
|
|
||||||
break
|
|
||||||
except ValueError:
|
|
||||||
continue
|
|
||||||
|
|
||||||
with test_server_running(options.force, external_host):
|
|
||||||
# Important: do next things inside the `with` block, when Django
|
|
||||||
# will be pointing at the test database.
|
|
||||||
reset_database()
|
|
||||||
subprocess.check_call('tools/setup/generate-test-credentials')
|
|
||||||
|
|
||||||
# RUN THE TESTS!!!
|
|
||||||
if loop_cnt:
|
|
||||||
run_loops(loop_cnt)
|
|
||||||
ret = 0
|
|
||||||
else:
|
|
||||||
ret = run_tests()
|
|
||||||
|
|
||||||
if ret != 0:
|
|
||||||
print("""
|
|
||||||
The Casper frontend tests failed! For help debugging, read:
|
|
||||||
https://zulip.readthedocs.io/en/latest/testing/testing-with-casper.html""", file=sys.stderr)
|
|
||||||
if os.environ.get("CIRCLECI"):
|
|
||||||
print("", file=sys.stderr)
|
|
||||||
print("In CircleCI, the Artifacts tab contains screenshots of the failure.", file=sys.stderr)
|
|
||||||
print("", file=sys.stderr)
|
|
||||||
|
|
||||||
sys.exit(ret)
|
|
||||||
|
|
||||||
external_host = "zulipdev.com:9981"
|
|
||||||
run_tests(options.tests, external_host)
|
|
||||||
sys.exit(0)
|
|
|
@ -90,7 +90,6 @@
|
||||||
"@typescript-eslint/eslint-plugin": "^3.1.0",
|
"@typescript-eslint/eslint-plugin": "^3.1.0",
|
||||||
"@typescript-eslint/parser": "^3.1.0",
|
"@typescript-eslint/parser": "^3.1.0",
|
||||||
"babel-plugin-rewire-ts": "^1.3.3",
|
"babel-plugin-rewire-ts": "^1.3.3",
|
||||||
"casperjs": "casperjs/casperjs",
|
|
||||||
"difflib": "^0.2.4",
|
"difflib": "^0.2.4",
|
||||||
"eslint": "^7.2.0",
|
"eslint": "^7.2.0",
|
||||||
"eslint-config-prettier": "^6.11.0",
|
"eslint-config-prettier": "^6.11.0",
|
||||||
|
|
|
@ -4,12 +4,6 @@ module.exports = {
|
||||||
bracketSpacing: false,
|
bracketSpacing: false,
|
||||||
trailingComma: "all",
|
trailingComma: "all",
|
||||||
overrides: [
|
overrides: [
|
||||||
{
|
|
||||||
files: ["frontend_tests/casper_tests/*.js", "frontend_tests/casper_lib/*.js"],
|
|
||||||
options: {
|
|
||||||
trailingComma: "es5",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
files: ["tsconfig.json"],
|
files: ["tsconfig.json"],
|
||||||
options: {
|
options: {
|
||||||
|
|
|
@ -18,18 +18,6 @@ set -x
|
||||||
PYTHONWARNINGS=ignore ./tools/check-capitalization --no-generate
|
PYTHONWARNINGS=ignore ./tools/check-capitalization --no-generate
|
||||||
PYTHONWARNINGS=ignore ./tools/check-frontend-i18n --no-generate
|
PYTHONWARNINGS=ignore ./tools/check-frontend-i18n --no-generate
|
||||||
|
|
||||||
# Disabled because of the frequently flaky
|
|
||||||
# behaviour of it.
|
|
||||||
# General pattern of the flaky failure is
|
|
||||||
#
|
|
||||||
# FAIL "#zhome" never appeared in 5000ms
|
|
||||||
# type: uncaughtError
|
|
||||||
# file: /home/circleci/zulip/frontend_tests/casper_tests/04-compose.js
|
|
||||||
# error: "#zhome" never appeared in 5000ms
|
|
||||||
# stack: not provided
|
|
||||||
#
|
|
||||||
# ./tools/test-js-with-casper --xunit-export
|
|
||||||
|
|
||||||
./tools/test-js-with-puppeteer
|
./tools/test-js-with-puppeteer
|
||||||
|
|
||||||
# NB: Everything here should be in `tools/test-all`. If there's a
|
# NB: Everything here should be in `tools/test-all`. If there's a
|
||||||
|
|
|
@ -87,7 +87,7 @@ base_port = 9991
|
||||||
if options.test:
|
if options.test:
|
||||||
base_port = 9981
|
base_port = 9981
|
||||||
settings_module = "zproject.test_settings"
|
settings_module = "zproject.test_settings"
|
||||||
# Don't auto-reload when running casper tests
|
# Don't auto-reload when running puppeteer tests
|
||||||
runserver_args = ['--noreload']
|
runserver_args = ['--noreload']
|
||||||
else:
|
else:
|
||||||
settings_module = "zproject.settings"
|
settings_module = "zproject.settings"
|
||||||
|
|
|
@ -5,10 +5,10 @@ cd "$(dirname "$0")"/../..
|
||||||
|
|
||||||
email=desdemona@zulip.com
|
email=desdemona@zulip.com
|
||||||
|
|
||||||
mkdir -p var/casper
|
mkdir -p var/puppeteer
|
||||||
|
|
||||||
password=$(./manage.py print_initial_password "$email" | grep -F "$email" | awk '{ print $2 }')
|
password=$(./manage.py print_initial_password "$email" | grep -F "$email" | awk '{ print $2 }')
|
||||||
cat > var/casper/test_credentials.js <<EOF
|
cat > var/puppeteer/test_credentials.js <<EOF
|
||||||
// Generated by tools/setup/generate-test-credentials
|
// Generated by tools/setup/generate-test-credentials
|
||||||
var test_credentials = {default_user: {username: '$email', password: '$password'}};
|
var test_credentials = {default_user: {username: '$email', password: '$password'}};
|
||||||
try { exports.test_credentials = test_credentials; } catch (e) {}
|
try { exports.test_credentials = test_credentials; } catch (e) {}
|
||||||
|
|
|
@ -74,6 +74,5 @@ run ./manage.py makemessages --locale en
|
||||||
run env PYTHONWARNINGS=ignore ./tools/check-capitalization --no-generate
|
run env PYTHONWARNINGS=ignore ./tools/check-capitalization --no-generate
|
||||||
run env PYTHONWARNINGS=ignore ./tools/check-frontend-i18n --no-generate
|
run env PYTHONWARNINGS=ignore ./tools/check-frontend-i18n --no-generate
|
||||||
run ./tools/test-js-with-puppeteer $FORCEARG
|
run ./tools/test-js-with-puppeteer $FORCEARG
|
||||||
run ./tools/test-js-with-casper $FORCEARG
|
|
||||||
|
|
||||||
printf '\n\e[32mAll OK!\e[0m\n'
|
printf '\n\e[32mAll OK!\e[0m\n'
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
../frontend_tests/run-casper
|
|
|
@ -44,4 +44,4 @@ API_FEATURE_LEVEL = 32
|
||||||
# historical commits sharing the same major version, in which case a
|
# historical commits sharing the same major version, in which case a
|
||||||
# minor version bump suffices.
|
# minor version bump suffices.
|
||||||
|
|
||||||
PROVISION_VERSION = '98.1'
|
PROVISION_VERSION = '99.0'
|
||||||
|
|
|
@ -2711,10 +2711,6 @@ caseless@~0.12.0:
|
||||||
resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc"
|
resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc"
|
||||||
integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=
|
integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=
|
||||||
|
|
||||||
casperjs@casperjs/casperjs:
|
|
||||||
version "1.1.4"
|
|
||||||
resolved "https://codeload.github.com/casperjs/casperjs/tar.gz/4c236d0e139ca5dc90c91acd364445025e7a1522"
|
|
||||||
|
|
||||||
ccount@^1.0.0:
|
ccount@^1.0.0:
|
||||||
version "1.0.5"
|
version "1.0.5"
|
||||||
resolved "https://registry.yarnpkg.com/ccount/-/ccount-1.0.5.tgz#ac82a944905a65ce204eb03023157edf29425c17"
|
resolved "https://registry.yarnpkg.com/ccount/-/ccount-1.0.5.tgz#ac82a944905a65ce204eb03023157edf29425c17"
|
||||||
|
|
Loading…
Reference in New Issue