mirror of
https://github.com/zulip/zulip.git
synced 2025-10-25 00:53:56 +00:00
Compare commits
240 Commits
5.0-rc1-br
...
shared-0.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3ff2bcf62a | ||
|
|
7de1e7c477 | ||
|
|
b7f670f5a0 | ||
|
|
2a240d3e19 | ||
|
|
efdf2c8fe3 | ||
|
|
71c12e313c | ||
|
|
da6d687215 | ||
|
|
58799c6ca1 | ||
|
|
8d9e6d6b87 | ||
|
|
935cb605a5 | ||
|
|
ca38b33346 | ||
|
|
0008a76703 | ||
|
|
d9bf8baca1 | ||
|
|
46b19fe8bd | ||
|
|
c1103e4c7b | ||
|
|
c8dba33408 | ||
|
|
6ea9947991 | ||
|
|
12e8f0f5ea | ||
|
|
d308c694ba | ||
|
|
836529f826 | ||
|
|
20e6315705 | ||
|
|
c789097184 | ||
|
|
52cf557d2b | ||
|
|
35ee5679d6 | ||
|
|
f054d217c2 | ||
|
|
fecc557836 | ||
|
|
e06e05acac | ||
|
|
a907c10509 | ||
|
|
2455077346 | ||
|
|
245288df1e | ||
|
|
244f34b66e | ||
|
|
2c558750de | ||
|
|
13da2c2fb7 | ||
|
|
a7f13ba723 | ||
|
|
7cbe9665b6 | ||
|
|
a234fe9c4c | ||
|
|
6b5ce3579c | ||
|
|
f04fb51ecc | ||
|
|
cbfe2707f4 | ||
|
|
1b55ff79c9 | ||
|
|
e4d051b5f4 | ||
|
|
56b6b71236 | ||
|
|
012e2d29a2 | ||
|
|
ca506f71dc | ||
|
|
20bb1b70d1 | ||
|
|
2a1e08759b | ||
|
|
f6d27562fa | ||
|
|
5e128e7cad | ||
|
|
8d242f3467 | ||
|
|
41b7b3d7a4 | ||
|
|
9dd8d13e0c | ||
|
|
9ce924a3a6 | ||
|
|
2d71858380 | ||
|
|
55882fb343 | ||
|
|
1f68c73e66 | ||
|
|
078d966c64 | ||
|
|
eae4643cb4 | ||
|
|
141b0c4cec | ||
|
|
781107308d | ||
|
|
2762121162 | ||
|
|
548dd5a402 | ||
|
|
83c90c53df | ||
|
|
e3600900c0 | ||
|
|
ab3196470f | ||
|
|
f9f111f950 | ||
|
|
219e213c60 | ||
|
|
b493224cda | ||
|
|
08dddeac7d | ||
|
|
8d78f356e6 | ||
|
|
c5bb9cb08a | ||
|
|
7e03ed9391 | ||
|
|
72cf5bd90d | ||
|
|
417766a3e3 | ||
|
|
bd936a837a | ||
|
|
182c00248d | ||
|
|
f3488c540b | ||
|
|
e16ede4622 | ||
|
|
330f0649d7 | ||
|
|
e88ca470ac | ||
|
|
07df504c79 | ||
|
|
b7747e51dd | ||
|
|
1b4ff0631c | ||
|
|
58184fc2a9 | ||
|
|
d006b6cc3d | ||
|
|
b799ec32b0 | ||
|
|
abea1f4598 | ||
|
|
d149af936d | ||
|
|
4f93b4b6e4 | ||
|
|
0d90bb2569 | ||
|
|
00332fd49d | ||
|
|
2dd0b386fe | ||
|
|
7dd2ed85db | ||
|
|
ec54b1e5a8 | ||
|
|
cab37b4aca | ||
|
|
4befe4fc30 | ||
|
|
4d03a1b0b7 | ||
|
|
c121bec188 | ||
|
|
6087f0daf1 | ||
|
|
24070c7ad8 | ||
|
|
6fcbe4091d | ||
|
|
9a7fadbbeb | ||
|
|
babe5ed44a | ||
|
|
1ac0035f8c | ||
|
|
d89b5042a9 | ||
|
|
630abf57d9 | ||
|
|
b9e428dd5d | ||
|
|
abed174b12 | ||
|
|
d7b59c86ce | ||
|
|
4d4c320a07 | ||
|
|
b67288db67 | ||
|
|
453cb409cf | ||
|
|
ba7695e5de | ||
|
|
2f929bee2f | ||
|
|
8d40199729 | ||
|
|
ceb9dd5854 | ||
|
|
3f0b0ee88c | ||
|
|
373f700736 | ||
|
|
cc32a3afff | ||
|
|
7bc0e70693 | ||
|
|
040363f6c7 | ||
|
|
cf5a70a958 | ||
|
|
64ec62b15c | ||
|
|
61cf9d1843 | ||
|
|
e2f4b284db | ||
|
|
f39ee5a16c | ||
|
|
a4d0f03319 | ||
|
|
c0cc98c6a8 | ||
|
|
394f1eadde | ||
|
|
086c0328bd | ||
|
|
b70b925716 | ||
|
|
ca395227b2 | ||
|
|
ddab1d9b07 | ||
|
|
210268f264 | ||
|
|
1b1c479333 | ||
|
|
517b2a5e10 | ||
|
|
4f735aeb0e | ||
|
|
a2c8be9cd5 | ||
|
|
0943b38300 | ||
|
|
3df0cacd9e | ||
|
|
6063d063b7 | ||
|
|
0844a80d66 | ||
|
|
f0c680e9c0 | ||
|
|
86dacee91e | ||
|
|
b7edd5df2f | ||
|
|
7a25a80242 | ||
|
|
1b3e003b53 | ||
|
|
7c60ff384d | ||
|
|
27d669ab62 | ||
|
|
78af84f6a1 | ||
|
|
3989bfe1ff | ||
|
|
b925c2f3de | ||
|
|
7d2abdf56a | ||
|
|
f0409517b3 | ||
|
|
2e69b66fec | ||
|
|
f46b231c0c | ||
|
|
9f843b924a | ||
|
|
4da2f154e0 | ||
|
|
aebd81c440 | ||
|
|
2328a81f55 | ||
|
|
e16043547b | ||
|
|
2be2393d3e | ||
|
|
be6ab93b37 | ||
|
|
2bc1cd6ab4 | ||
|
|
ed3569a470 | ||
|
|
279b99ab23 | ||
|
|
57fa62ae4b | ||
|
|
5393ce11c7 | ||
|
|
6b00c748fd | ||
|
|
a117b224a7 | ||
|
|
b4507df8fa | ||
|
|
fddd83394e | ||
|
|
4f3894f9f1 | ||
|
|
9761711351 | ||
|
|
af5d0d6f5e | ||
|
|
88e0d1b111 | ||
|
|
9e850b08f3 | ||
|
|
3be023911b | ||
|
|
1bd5723cd2 | ||
|
|
6b91652d9a | ||
|
|
6558655fc6 | ||
|
|
bdd2f35d05 | ||
|
|
17699bea44 | ||
|
|
bedc7c2986 | ||
|
|
307a7d8104 | ||
|
|
780bda0d40 | ||
|
|
33af1c1cd6 | ||
|
|
83d02af9aa | ||
|
|
a967a86b10 | ||
|
|
0d117ab033 | ||
|
|
c4bb181056 | ||
|
|
9d460a513e | ||
|
|
a9d7a15ce2 | ||
|
|
5e8c8bfc0f | ||
|
|
6be44a6971 | ||
|
|
74780d24d5 | ||
|
|
507851c25a | ||
|
|
0d31781aed | ||
|
|
1fb4dd2eee | ||
|
|
211f137fc8 | ||
|
|
ecf557eab9 | ||
|
|
84cdf03bb2 | ||
|
|
5fb3aa4f44 | ||
|
|
b06178767b | ||
|
|
7fcac3288b | ||
|
|
d3dca4f7de | ||
|
|
f8146cfaa1 | ||
|
|
e45cebd636 | ||
|
|
26d97ce7e3 | ||
|
|
29e4342738 | ||
|
|
db5f39c506 | ||
|
|
a5ec78c6ab | ||
|
|
1168258285 | ||
|
|
b0217d0ec6 | ||
|
|
7aa03e9d2a | ||
|
|
7d4b02738d | ||
|
|
e2e645a183 | ||
|
|
995cbc69b4 | ||
|
|
6aec27e646 | ||
|
|
e32ec3f7eb | ||
|
|
215791db1e | ||
|
|
eb7770565a | ||
|
|
8ef2c0a604 | ||
|
|
da0658967c | ||
|
|
5d77381667 | ||
|
|
44844743cd | ||
|
|
a3d89e049a | ||
|
|
62e049b25a | ||
|
|
c35a783c35 | ||
|
|
2c26ad3714 | ||
|
|
6489c832a3 | ||
|
|
6b0876063f | ||
|
|
bffd73fe44 | ||
|
|
599a70d6f4 | ||
|
|
097852bb06 | ||
|
|
a9f83a5805 | ||
|
|
d162bd17a9 | ||
|
|
4b712b49ef | ||
|
|
f84a2c08d5 | ||
|
|
f21842e920 | ||
|
|
dfab993e7d |
@@ -2,4 +2,4 @@
|
||||
> 0.15% in US
|
||||
last 2 versions
|
||||
Firefox ESR
|
||||
not dead
|
||||
not dead and supports async-functions
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
"eslint:recommended",
|
||||
"plugin:import/errors",
|
||||
"plugin:import/warnings",
|
||||
"plugin:no-jquery/recommended",
|
||||
"plugin:no-jquery/deprecated",
|
||||
"plugin:unicorn/recommended",
|
||||
"prettier"
|
||||
],
|
||||
@@ -15,9 +17,15 @@
|
||||
"warnOnUnsupportedTypeScriptVersion": false,
|
||||
"sourceType": "unambiguous"
|
||||
},
|
||||
"plugins": ["formatjs"],
|
||||
"plugins": ["formatjs", "no-jquery"],
|
||||
"settings": {
|
||||
"additionalFunctionNames": ["$t", "$t_html"]
|
||||
"additionalFunctionNames": ["$t", "$t_html"],
|
||||
"no-jquery": {
|
||||
"collectionReturningPlugins": {
|
||||
"expectOne": "always"
|
||||
},
|
||||
"variablePattern": "^\\$(?!t$|t_html$)."
|
||||
}
|
||||
},
|
||||
"reportUnusedDisableDirectives": true,
|
||||
"rules": {
|
||||
@@ -65,6 +73,7 @@
|
||||
"no-implied-eval": "error",
|
||||
"no-inner-declarations": "off",
|
||||
"no-iterator": "error",
|
||||
"no-jquery/no-parse-html-literal": "error",
|
||||
"no-label-var": "error",
|
||||
"no-labels": "error",
|
||||
"no-loop-func": "error",
|
||||
@@ -120,6 +129,12 @@
|
||||
"yoda": "error"
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["frontend_tests/node_tests/**", "frontend_tests/zjsunit/**"],
|
||||
"rules": {
|
||||
"no-jquery/no-selector-prop": "off"
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": ["frontend_tests/puppeteer_lib/**", "frontend_tests/puppeteer_tests/**"],
|
||||
"globals": {
|
||||
|
||||
42
.mailmap
42
.mailmap
@@ -1,36 +1,73 @@
|
||||
# This file teaches `git log` and friends the canonical names
|
||||
# and email addresses to use for our contributors.
|
||||
#
|
||||
# For details on the format, see:
|
||||
# https://git.github.io/htmldocs/gitmailmap.html
|
||||
#
|
||||
# Handy commands for examining or adding to this file:
|
||||
#
|
||||
# # shows all names/emails after mapping, sorted:
|
||||
# $ git shortlog -es | sort -k2
|
||||
#
|
||||
# # shows raw names/emails, filtered by mapped name:
|
||||
# $ git log --format='%an %ae' --author=$NAME | uniq -c
|
||||
|
||||
Adam Benesh <Adam.Benesh@gmail.com> <Adam-Daniel.Benesh@t-systems.com>
|
||||
Adam Benesh <Adam.Benesh@gmail.com>
|
||||
Alex Vandiver <alexmv@zulip.com> <alex@chmrr.net>
|
||||
Alex Vandiver <alexmv@zulip.com> <github@chmrr.net>
|
||||
Allen Rabinovich <allenrabinovich@yahoo.com> <allenr@humbughq.com>
|
||||
Allen Rabinovich <allenrabinovich@yahoo.com> <allenr@zulip.com>
|
||||
Alya Abbott <alya@zulip.com> <2090066+alya@users.noreply.github.com>
|
||||
Aman Agrawal <amanagr@zulip.com> <f2016561@pilani.bits-pilani.ac.in>
|
||||
Anders Kaseorg <anders@zulip.com> <anders@zulipchat.com>
|
||||
Anders Kaseorg <anders@zulip.com> <andersk@mit.edu>
|
||||
Aryan Shridhar <aryanshridhar7@gmail.com> <53977614+aryanshridhar@users.noreply.github.com>
|
||||
Aryan Shridhar <aryanshridhar7@gmail.com>
|
||||
Ashwat Kumar Singh <ashwat.kumarsingh.met20@itbhu.ac.in>
|
||||
Austin Riba <austin@zulip.com> <austin@m51.io>
|
||||
BIKI DAS <bikid475@gmail.com>
|
||||
Brock Whittaker <brock@zulipchat.com> <bjwhitta@asu.edu>
|
||||
Brock Whittaker <brock@zulipchat.com> <brockwhittaker@Brocks-MacBook.local>
|
||||
Brock Whittaker <brock@zulipchat.com> <brock@zulipchat.org>
|
||||
Chris Bobbe <cbobbe@zulip.com> <cbobbe@zulipchat.com>
|
||||
Chris Bobbe <cbobbe@zulip.com> <csbobbe@gmail.com>
|
||||
Eeshan Garg <eeshan@zulip.com> <jerryguitarist@gmail.com>
|
||||
Greg Price <greg@zulip.com> <gnprice@gmail.com>
|
||||
Greg Price <greg@zulip.com> <greg@zulipchat.com>
|
||||
Greg Price <greg@zulip.com> <price@mit.edu>
|
||||
Jai soni <jai_s@me.iitr.ac.in>
|
||||
Jai soni <jai_s@me.iitr.ac.in> <76561593+jai2201@users.noreply.github.com>
|
||||
Jeff Arnold <jbarnold@gmail.com> <jbarnold@humbughq.com>
|
||||
Jeff Arnold <jbarnold@gmail.com> <jbarnold@zulip.com>
|
||||
Jessica McKellar <jesstess@mit.edu> <jesstess@humbughq.com>
|
||||
Jessica McKellar <jesstess@mit.edu> <jesstess@zulip.com>
|
||||
Julia Bichler <julia.bichler@tum.de> <74348920+juliaBichler01@users.noreply.github.com>
|
||||
Kevin Mehall <km@kevinmehall.net> <kevin@humbughq.com>
|
||||
Kevin Mehall <km@kevinmehall.net> <kevin@zulip.com>
|
||||
Kevin Scott <kevin.scott.98@gmail.com>
|
||||
Lauryn Menard <lauryn@zulip.com> <lauryn.menard@gmail.com>
|
||||
Mateusz Mandera <mateusz.mandera@zulip.com> <mateusz.mandera@protonmail.com>
|
||||
m-e-l-u-h-a-n <purushottam.tiwari.cd.cse19@itbhu.ac.in>
|
||||
Palash Raghuwanshi <singhpalash0@gmail.com>
|
||||
Parth <mittalparth22@gmail.com>
|
||||
Priyam Seth <sethpriyam1@gmail.com> <b19188@students.iitmandi.ac.in>
|
||||
Ray Kraesig <rkraesig@zulip.com> <rkraesig@zulipchat.com>
|
||||
Reid Barton <rwbarton@gmail.com> <rwbarton@humbughq.com>
|
||||
Rishi Gupta <rishig@zulipchat.com> <rishig+git@mit.edu>
|
||||
Rishi Gupta <rishig@zulipchat.com> <rishig@kandralabs.com>
|
||||
Rishi Gupta <rishig@zulipchat.com> <rishig@users.noreply.github.com>
|
||||
Reid Barton <rwbarton@gmail.com> <rwbarton@humbughq.com>
|
||||
Rishabh Maheshwari <b20063@students.iitmandi.ac.in>
|
||||
Sayam Samal <samal.sayam@gmail.com>
|
||||
Scott Feeney <scott@oceanbase.org> <scott@humbughq.com>
|
||||
Scott Feeney <scott@oceanbase.org> <scott@zulip.com>
|
||||
Shlok Patel <shlokcpatel2001@gmail.com>
|
||||
Steve Howell <showell@zulip.com> <showell30@yahoo.com>
|
||||
Steve Howell <showell@zulip.com> <showell@yahoo.com>
|
||||
Steve Howell <showell@zulip.com> <showell@zulipchat.com>
|
||||
Steve Howell <showell@zulip.com> <steve@humbughq.com>
|
||||
Steve Howell <showell@zulip.com> <steve@zulip.com>
|
||||
strifel <info@strifel.de>
|
||||
Tim Abbott <tabbott@zulip.com> <tabbott@dropbox.com>
|
||||
Tim Abbott <tabbott@zulip.com> <tabbott@humbughq.com>
|
||||
Tim Abbott <tabbott@zulip.com> <tabbott@mit.edu>
|
||||
@@ -41,3 +78,6 @@ Alya Abbott <alya@zulip.com> <alyaabbott@elance-odesk.com>
|
||||
Sahil Batra <sahil@zulip.com> <sahilbatra839@gmail.com>
|
||||
Yash RE <33805964+YashRE42@users.noreply.github.com> <YashRE42@github.com>
|
||||
Yash RE <33805964+YashRE42@users.noreply.github.com>
|
||||
Yogesh Sirsat <yogeshsirsat56@gmail.com>
|
||||
Zeeshan Equbal <equbalzeeshan@gmail.com> <54993043+zee-bit@users.noreply.github.com>
|
||||
Zeeshan Equbal <equbalzeeshan@gmail.com>
|
||||
|
||||
@@ -219,6 +219,61 @@ prefix when you think it's time for someone else to review your work.
|
||||
[git-guide]: https://zulip.readthedocs.io/en/latest/git/
|
||||
[git-guide-make-pr]: https://zulip.readthedocs.io/en/latest/git/pull-requests.html
|
||||
|
||||
### Stages of a pull request
|
||||
|
||||
Your pull request will likely go through several stages of review.
|
||||
|
||||
1. If your PR makes user-facing changes, the UI and user experience may be
|
||||
reviewed early on, without reference to the code. You will get feedback on
|
||||
any user-facing bugs in the implementation. To minimize the number of review
|
||||
round-trips, make sure to [thoroughly
|
||||
test](https://zulip.readthedocs.io/en/latest/contributing/code-reviewing.html#manual-testing)
|
||||
your own PR prior to asking for review.
|
||||
2. There may be choices made in the implementation that the reviewer
|
||||
will ask you to revisit. This process will go more smoothly if you
|
||||
specifically call attention to the decisions you made while
|
||||
drafting the PR and any points about which you are uncertain. The
|
||||
PR description and comments on your own PR are good ways to do this.
|
||||
3. Oftentimes, seeing an initial implementation will make it clear that the
|
||||
product design for a feature needs to be revised, or that additional changes
|
||||
are needed. The reviewer may therefore ask you to amend or change the
|
||||
implementation. Some changes may be blockers for getting the PR merged, while
|
||||
others may be improvements that can happen afterwards. Feel free to ask if
|
||||
it's unclear which type of feedback you're getting. (Follow-ups can be a
|
||||
great next issue to work on!)
|
||||
4. In addition to any UI/user experience review, all PRs will go through one or
|
||||
more rounds of code review. Your code may initially be [reviewed by other
|
||||
contributors](https://zulip.readthedocs.io/en/latest/contributing/code-reviewing.html).
|
||||
This helps us make good use of project maintainers' time, and helps you make
|
||||
progress on the PR by getting more frequent feedback. A project maintainer
|
||||
may leave a comment asking someone with expertise in the area you're working
|
||||
on to review your work.
|
||||
5. Final code review and integration for server and webapp PRs is generally done
|
||||
by `@timabbott`.
|
||||
|
||||
#### How to help move the review process forward
|
||||
|
||||
The key to keeping your review moving through the review process is to:
|
||||
|
||||
- Address _all_ the feedback to the best of your ability.
|
||||
- Make it clear when the requested changes have been made
|
||||
and you believe it's time for another look.
|
||||
- Make it as easy as possible to review the changes you made.
|
||||
|
||||
In order to do this, when you believe you have addressed the previous round of
|
||||
feedback on your PR as best you can, post an comment asking reviewers to take
|
||||
another look. Your comment should make it easy to understand what has been done
|
||||
and what remains by:
|
||||
|
||||
- Summarizing the changes made since the last review you received.
|
||||
- Highlighting remaining questions or decisions, with links to any relevant
|
||||
chat.zulip.org threads.
|
||||
- Providing updated screenshots and information on manual testing if
|
||||
appropriate.
|
||||
|
||||
The easier it is to review your work, the more likely you are to receive quick
|
||||
feedback.
|
||||
|
||||
### Beyond the first issue
|
||||
|
||||
To find a second issue to work on, we recommend looking through issues with the same
|
||||
@@ -252,25 +307,18 @@ labels.
|
||||
1. **Double-check that you have addressed all the feedback**, including any comments
|
||||
on [Git commit
|
||||
discipline](https://zulip.readthedocs.io/en/latest/contributing/version-control.html#commit-discipline).
|
||||
2. If all the feedback has been addressed, did you leave a comment explaining that
|
||||
you have done so and **requesting another review**? If not, it may not be a
|
||||
clear to project maintainers that your PR is ready for another look.
|
||||
3. It is common for PRs to require **multiple rounds of review**. For example,
|
||||
prior to getting code review from project maintainers, you may receive
|
||||
feedback on the UI (without regard for the implementation), and your code
|
||||
may be [reviewed by other
|
||||
contributors](https://zulip.readthedocs.io/en/latest/contributing/code-reviewing.html).
|
||||
This helps us make good use of project maintainers' time, and helps you
|
||||
make progress on the PR by getting more frequent feedback.
|
||||
2. If all the feedback has been addressed, did you [leave a
|
||||
comment](https://zulip.readthedocs.io/en/latest/overview/contributing.html#how-to-help-move-the-review-process-forward)
|
||||
explaining that you have done so and **requesting another review**? If not,
|
||||
it may not be clear to project maintainers or reviewers that your PR is
|
||||
ready for another look.
|
||||
3. There may be a pause between initial rounds of review for your PR and final
|
||||
review by project maintainers. This is normal, and we encourage you to **work
|
||||
on other issues** while you wait.
|
||||
4. If you think the PR is ready and haven't seen any updates for a couple
|
||||
of weeks, it can be helpful to post a **comment summarizing your
|
||||
understanding of the state of the review process**. Your comment should
|
||||
make it easy to understand what has been done and what remains by:
|
||||
- Summarizing the changes made since the last review you received.
|
||||
- Highlighting remaining questions or decisions, with links to any
|
||||
relevant chat.zulip.org threads.
|
||||
- Providing updated screenshots and information on manual testing if
|
||||
appropriate.
|
||||
of weeks, it can be helpful to **leave another comment**. Summarize the
|
||||
overall state of the review process and your work, and indicate that you
|
||||
are waiting for a review.
|
||||
5. Finally, **Zulip project maintainers are people too**! They may be busy
|
||||
with other work, and sometimes they might even take a vacation. ;) It can
|
||||
occasionally take a few weeks for a PR in the final stages of the review
|
||||
|
||||
@@ -15,7 +15,6 @@ module.exports = {
|
||||
"@babel/preset-env",
|
||||
{
|
||||
corejs: "3.20",
|
||||
loose: true, // Loose mode for…of loops are 5× faster in Firefox
|
||||
shippedProposals: true,
|
||||
useBuiltIns: "usage",
|
||||
},
|
||||
|
||||
@@ -191,7 +191,7 @@ def read_stripe_fixture(
|
||||
requestor.interpret_response(
|
||||
fixture["http_body"], fixture["http_status"], fixture["headers"]
|
||||
)
|
||||
return stripe.util.convert_to_stripe_object(fixture) # type: ignore[attr-defined] # missing from stubs
|
||||
return stripe.util.convert_to_stripe_object(fixture)
|
||||
|
||||
return _read_stripe_fixture
|
||||
|
||||
|
||||
@@ -91,7 +91,7 @@ Files: static/third/marked/*
|
||||
Copyright: 2011-2013, Christopher Jeffrey
|
||||
License: Expat
|
||||
|
||||
Files: static/assets/icons/ellipsis-v-solid.svg
|
||||
Files: static/shared/icons/ellipsis-v-solid.svg
|
||||
Copyright: 2017 Fonticons, Inc.
|
||||
License: CC-BY-4.0
|
||||
Comment: This icon is picked from Version 5.13.0 of Font Awesome
|
||||
@@ -113,6 +113,11 @@ Files: static/audio/notification_sounds/*
|
||||
Copyright: 2021 Stefan Mertens
|
||||
License: CC0-1.0
|
||||
|
||||
Files: static/shared/icons/globe.svg
|
||||
Source: https://github.com/ionic-team/ionicons/blob/v5.5.2/src/svg/earth.svg, modified to increase the width of the globe outline.
|
||||
Copyright: 2015-present Ionic (http://ionic.io/)
|
||||
License: Expat
|
||||
|
||||
License: Apache-2.0
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,11 +1,23 @@
|
||||
# Version history
|
||||
|
||||
This page the release history for the Zulip server. See also the
|
||||
[Zulip release lifecycle](release-lifecycle.md).
|
||||
[Zulip release lifecycle](../overview/release-lifecycle.md).
|
||||
|
||||
## Zulip 6.x series
|
||||
|
||||
### 6.0 -- unreleased
|
||||
|
||||
This section is an incomplete draft of the release notes for the next
|
||||
major release, and is only updated occasionally. See the [commit
|
||||
log][commit-log] for an up-to-date list of raw changes.
|
||||
|
||||
#### Upgrade notes for 6.0
|
||||
|
||||
- None yet.
|
||||
|
||||
## Zulip 5.x series
|
||||
|
||||
### 5.0-rc1 -- March 15, 2022
|
||||
### 5.0 -- 2022-03-29
|
||||
|
||||
This section is an incomplete draft of the release notes for the next
|
||||
major release, and is only updated occasionally. See the [commit
|
||||
@@ -42,8 +54,13 @@ log][commit-log] for an up-to-date list of raw changes.
|
||||
preference settings for new users joining the organization.
|
||||
- Most permissions settings now support choosing which roles have the
|
||||
permission, rather than just allowing administrators or everyone.
|
||||
- Permanent links to conversations now correctly redirect if the
|
||||
target message has been moved to a new stream or topic.
|
||||
- Added a data import tool for migrating from Rocket.Chat. Mattermost
|
||||
data import now supports importing uploaded files.
|
||||
- Improved handling of messages containing many images; now up to 20
|
||||
images can be previewed in a single message (up from 5), and a new
|
||||
grid layout will be used.
|
||||
- OpenID Connect joins SAML, LDAP, Google, GitHub, Azure Active
|
||||
Directory, and more as a supported Single Sign-On provider.
|
||||
- SAML authentication now supports syncing custom profile
|
||||
@@ -87,6 +104,7 @@ log][commit-log] for an up-to-date list of raw changes.
|
||||
Sonarr, SonarQube.
|
||||
- Message edit notifications now indicate how many messages were
|
||||
moved, when only part of a topic was moved.
|
||||
- Muted topic records are now moved when an entire topic is moved.
|
||||
- Search views that don't mark messages as read now have an
|
||||
explanatory notice if any unread messages are present.
|
||||
- Added new "Scroll to bottom" widget hovering over the message feed.
|
||||
@@ -102,7 +120,8 @@ log][commit-log] for an up-to-date list of raw changes.
|
||||
- Redesigned hover behavior for timestamps and time mentions.
|
||||
- Messages sent by muted users can now be rehidden after being
|
||||
revealed. One can also now mute deactivated users.
|
||||
- Rewrote Help Center guides for new organizations and users.
|
||||
- Rewrote Help Center guides for new organizations and users, and made
|
||||
hundreds of other improvements to Help Center content and organization.
|
||||
- Reimplemented the image lightbox's pan/zoom functionality to be
|
||||
nicer, allowing us to enable it be default.
|
||||
- Added styled loading page for the web application.
|
||||
@@ -110,8 +129,9 @@ log][commit-log] for an up-to-date list of raw changes.
|
||||
- Notifications now differentiate user group mentions from personal mentions.
|
||||
- Added support for configuring how long the server should wait before
|
||||
sending email notifications after a mention or PM.
|
||||
- Improved integrations: GitHub, Grafana, PagerDuty.
|
||||
- Improved various interaction details in Recent Topics.
|
||||
- Improved integrations: BigBlueButton, GitHub, Grafana, PagerDuty,
|
||||
and many more.
|
||||
- Improved various interaction and performance details in Recent Topics.
|
||||
- Improved styling for poll and todo list widgets.
|
||||
- Zulip now supports configuring the database name and username when
|
||||
using a remote Postgres server. Previously, these were hardcoded to "zulip".
|
||||
@@ -169,6 +189,7 @@ log][commit-log] for an up-to-date list of raw changes.
|
||||
- Fixed a bug where different messages in search results would be
|
||||
incorrectly shown with a shared recipient bar despite potentially
|
||||
not being temporally adjacent.
|
||||
- Fixed lightbox download button not working with the S3 upload backend.
|
||||
- Increased default retention period before permanently removing
|
||||
deleted messages from 7 days to 30 days.
|
||||
- Rate limiting now supports treating all Tor exit nodes as a single IP.
|
||||
@@ -177,9 +198,13 @@ log][commit-log] for an up-to-date list of raw changes.
|
||||
software from flagging invitations.
|
||||
- Added support for uploading animated PNGs as custom emoji.
|
||||
- Renamed "Night mode" to "Dark theme".
|
||||
- Added the mobile app's notification sound to desktop sound options,
|
||||
as "Chime".
|
||||
- Reworked the `manage.py help` interface to hide Django commands that are
|
||||
useless or harmful to run on a production system. Also deleted
|
||||
several useless management commands.
|
||||
- Improved help and functionality of several management commands. New
|
||||
create_realm management command supports some automation workflows.
|
||||
- Added `RealmAuditLog` logging for most administrative actions that
|
||||
were previously not tracked.
|
||||
- Added automated testing of the upgrade process from previous releases,
|
||||
@@ -1551,7 +1576,7 @@ Zulip installations; it has minimal changes for existing servers.
|
||||
disruption by running this migration first, before beginning the
|
||||
user-facing downtime. However, if you'd like to watch the downtime
|
||||
phase of the upgrade closely, we recommend
|
||||
[running them first manually](https://zulip.readthedocs.io/en/1.9.0/production/expensive-migrations.html)
|
||||
running them first manually
|
||||
as well as the usual trick of doing an apt upgrade first.
|
||||
|
||||
#### Full feature changelog
|
||||
@@ -1940,7 +1965,7 @@ running a version from before 1.7 should upgrade directly to 1.7.1.
|
||||
minimizes disruption by running these first, before beginning the
|
||||
user-facing downtime. However, if you'd like to watch the downtime
|
||||
phase of the upgrade closely, we recommend
|
||||
[running them first manually](https://zulip.readthedocs.io/en/1.9.0/production/expensive-migrations.html)
|
||||
running them first manually
|
||||
as well as the usual trick of doing an apt upgrade first.
|
||||
|
||||
- We've removed support for an uncommon legacy deployment model where
|
||||
@@ -2565,15 +2590,17 @@ running a version from before 1.7 should upgrade directly to 1.7.1.
|
||||
This section links to the upgrade notes from past releases, so you can
|
||||
easily read them all when upgrading across multiple releases.
|
||||
|
||||
- [Draft upgrade notes for 5.0](#upgrade-notes-for-50)
|
||||
- [Upgrade notes for 4.0](#upgrade-notes-for-40)
|
||||
- [Upgrade notes for 3.0](#upgrade-notes-for-30)
|
||||
- [Upgrade notes for 2.1.5](#upgrade-notes-for-215)
|
||||
- [Upgrade notes for 2.1.0](#upgrade-notes-for-210)
|
||||
- [Upgrade notes for 2.0.0](#upgrade-notes-for-200)
|
||||
- [Upgrade notes for 1.9.0](#upgrade-notes-for-190)
|
||||
- [Upgrade notes for 1.8.0](#upgrade-notes-for-180)
|
||||
- [Upgrade notes for 1.7.0](#upgrade-notes-for-170)
|
||||
- [Draft upgrade notes for 6.0](#upgrade-notes-for-60)
|
||||
|
||||
* [Upgrade notes for 5.0](#upgrade-notes-for-50)
|
||||
* [Upgrade notes for 4.0](#upgrade-notes-for-40)
|
||||
* [Upgrade notes for 3.0](#upgrade-notes-for-30)
|
||||
* [Upgrade notes for 2.1.5](#upgrade-notes-for-215)
|
||||
* [Upgrade notes for 2.1.0](#upgrade-notes-for-210)
|
||||
* [Upgrade notes for 2.0.0](#upgrade-notes-for-200)
|
||||
* [Upgrade notes for 1.9.0](#upgrade-notes-for-190)
|
||||
* [Upgrade notes for 1.8.0](#upgrade-notes-for-180)
|
||||
* [Upgrade notes for 1.7.0](#upgrade-notes-for-170)
|
||||
|
||||
[docker-zulip]: https://github.com/zulip/docker-zulip
|
||||
[commit-log]: https://github.com/zulip/zulip/commits/main
|
||||
|
||||
@@ -66,8 +66,8 @@ templating systems.
|
||||
|
||||
- `node_modules/` Third-party JavaScript installed via `yarn`.
|
||||
|
||||
- `static/assets/` For assets not to be served to the web (e.g. the system to
|
||||
generate our favicons).
|
||||
- `static/shared/icons/` Icons placed in this directory are compiled
|
||||
into an icon font.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -289,11 +289,23 @@ AUTH_LDAP_USER_SEARCH = LDAPSearchUnion(
|
||||
|
||||
You can restrict access to your Zulip server to a set of LDAP groups
|
||||
using the `AUTH_LDAP_REQUIRE_GROUP` and `AUTH_LDAP_DENY_GROUP`
|
||||
settings in `/etc/zulip/settings.py`. See the
|
||||
[upstream django-auth-ldap documentation][upstream-ldap-groups] for
|
||||
details.
|
||||
settings in `/etc/zulip/settings.py`.
|
||||
|
||||
[upstream-ldap-groups]: https://django-auth-ldap.readthedocs.io/en/latest/groups.html#limiting-access
|
||||
An example configation for Active Directory group restriction can be:
|
||||
|
||||
```
|
||||
import django_auth_ldap
|
||||
AUTH_LDAP_GROUP_TYPE = django_auth_ldap.config.ActiveDirectoryGroupType()
|
||||
|
||||
AUTH_LDAP_REQUIRE_GROUP = "cn=enabled,ou=groups,dc=example,dc=com"
|
||||
AUTH_LDAP_GROUP_SEARCH = LDAPSearch("ou=groups,dc=example,dc=com", ldap.SCOPE_SUBTREE, "(objectClass=groupOfNames)")
|
||||
```
|
||||
|
||||
Please note that `AUTH_LDAP_GROUP_TYPE` needs to be set to the correct
|
||||
group type for your LDAP server. See the [upstream django-auth-ldap
|
||||
documentation][upstream-ldap-groups] for details.
|
||||
|
||||
[upstream-ldap-groups]: https://django-auth-ldap.readthedocs.io/en/latest/groups.html
|
||||
|
||||
### Restricting LDAP user access to specific organizations
|
||||
|
||||
|
||||
@@ -274,6 +274,19 @@ class, and configure the `[http_proxy]` block as above.
|
||||
[smokescreen-acls]: https://github.com/stripe/smokescreen#acls
|
||||
[ssrf]: https://owasp.org/www-community/attacks/Server_Side_Request_Forgery
|
||||
|
||||
### S3 file storage requests and outgoing proxies
|
||||
|
||||
By default, the [S3 file storage backend][s3] bypasses the Smokescreen
|
||||
proxy, because when running on EC2 it may require metadata from the
|
||||
IMDS metadata endpoint, which resides on the internal IP address
|
||||
169.254.169.254 and would thus be blocked by Smokescreen.
|
||||
|
||||
If your S3-compatible storage backend requires use of Smokescreen or
|
||||
some other proxy, you can override this default by setting
|
||||
`S3_SKIP_PROXY = False` in `/etc/zulip/settings.py`.
|
||||
|
||||
[s3]: upload-backends.md#s3-backend-configuration
|
||||
|
||||
## Putting the Zulip application behind a reverse proxy
|
||||
|
||||
Zulip is designed to support being run behind a reverse proxy server.
|
||||
@@ -512,8 +525,9 @@ deployment. Zulip's configuration builds on top of `wal-g`, our
|
||||
[database backup solution][wal-g], and thus requires that it be
|
||||
configured for the primary and all secondary warm standby replicas.
|
||||
|
||||
Warm spare replicas should also have `wal-g` backups configured, and
|
||||
their primary replica and replication username set:
|
||||
In addition to having `wal-g` backups configured, warm standby
|
||||
replicas should configure the hostname of their primary replica, and
|
||||
username to use for replication, in `/etc/zulip/zulip.conf`:
|
||||
|
||||
```ini
|
||||
[postgresql]
|
||||
@@ -522,14 +536,14 @@ replication_primary = hostname-of-primary.example.com
|
||||
```
|
||||
|
||||
The `postgres` user on the replica will need to be able to
|
||||
authenticate as the `replicator` user, which may require further
|
||||
authenticate as the `replication_user` user, which may require further
|
||||
configuration of `pg_hba.conf` and client certificates on the replica.
|
||||
If you are using password authentication, you can set a
|
||||
`postgresql_replication_password` secret in
|
||||
`/etc/zulip/zulip-secrets.conf`.
|
||||
|
||||
[warm-standby]: https://www.postgresql.org/docs/current/warm-standby.html
|
||||
[wal-g]: export-and-import.md#backup-details
|
||||
[wal-g]: export-and-import.md#database-only-backup-tools
|
||||
|
||||
## System and deployment configuration
|
||||
|
||||
|
||||
@@ -161,25 +161,9 @@ included in the backups generated by Zulip's standard tools. The
|
||||
data includes:
|
||||
|
||||
- The PostgreSQL database. You can back this up with any standard
|
||||
database export or backup tool. Zulip has built-in support for taking
|
||||
daily incremental backups using
|
||||
[wal-g](https://github.com/wal-g/wal-g); these backups are stored for
|
||||
30 days in S3. If you have an Amazon S3 bucket you wish to store for
|
||||
storing the backups, edit `/etc/zulip/zulip-secrets.conf` on the
|
||||
PostgreSQL server to add:
|
||||
|
||||
```ini
|
||||
s3_region = # region to write to S3; defaults to EC2 host's region
|
||||
s3_backups_key = # aws public key; optional, if access not through role
|
||||
s3_backups_secret_key = # aws secret key; optional, if access not through role
|
||||
s3_backups_bucket = # name of S3 backup bucket
|
||||
```
|
||||
|
||||
After adding the secrets, run
|
||||
`/home/zulip/deployments/current/scripts/zulip-puppet-apply`. You
|
||||
can (and should) monitor that backups are running regularly via
|
||||
the Nagios plugin installed into
|
||||
`/usr/lib/nagios/plugins/zulip_postgresql_backups/check_postgresql_backup`.
|
||||
database export or backup tool; see
|
||||
[below](#database-only-backup-tools) for Zulip's built-in support
|
||||
for continuous point-in-time backups.
|
||||
|
||||
- Any user-uploaded files. If you're using S3 as storage for file
|
||||
uploads, this is backed up in S3. But if you have instead set
|
||||
@@ -201,16 +185,12 @@ data includes:
|
||||
To restore from a manual backup, the process is basically the reverse of the above:
|
||||
|
||||
- Install new server as normal by downloading a Zulip release tarball
|
||||
and then using `scripts/setup/install`. You don't need
|
||||
to run the `initialize-database` second stage which puts default
|
||||
data into the database.
|
||||
and then using `scripts/setup/install`. You should pass
|
||||
`--no-init-db` because we don't need to create a new database.
|
||||
|
||||
- Unpack to `/etc/zulip` the `settings.py` and `zulip-secrets.conf` files
|
||||
from your backups.
|
||||
|
||||
- If you ran `initialize-database` anyway above, you'll want to run
|
||||
`scripts/setup/postgresql-init-db` to drop the initial database first.
|
||||
|
||||
- Restore your database from the backup.
|
||||
|
||||
- Reconfigure rabbitmq to use the password from `secrets.conf`
|
||||
@@ -359,7 +339,7 @@ cd ~
|
||||
tar -xf /path/to/export/file/zulip-export-zcmpxfm6.tar.gz
|
||||
cd /home/zulip/deployments/current
|
||||
./manage.py import '' ~/zulip-export-zcmpxfm6
|
||||
# supervisorctl start all # Starts the Zulip server
|
||||
# ./scripts/start-server
|
||||
# ./manage.py reactivate_realm -r '' # Reactivates the organization
|
||||
```
|
||||
|
||||
@@ -451,3 +431,40 @@ rm -rf /home/zulip/uploads/*/2/
|
||||
```
|
||||
|
||||
Once that's done, you can simply re-run the import process.
|
||||
|
||||
## Database-only backup tools
|
||||
|
||||
The [Zulip-specific backup tool documented above](#backups) is perfect
|
||||
for an all-in-one backup solution, and can be used for nightly
|
||||
backups. For administrators wanting continuous point-in-time backups,
|
||||
Zulip has built-in support for taking daily incremental backups using
|
||||
[wal-g](https://github.com/wal-g/wal-g) and storing them in Amazon S3.
|
||||
By default, these backups are stored for 30 days.
|
||||
|
||||
Note these database backups, by themselves, do not constitute a full
|
||||
backup of the Zulip system! [See above](#backup-details) for other
|
||||
pieces which are necessary to back up a Zulip system.
|
||||
|
||||
To enable continuous point-in-time backups:
|
||||
|
||||
1. Edit `/etc/zulip/zulip-secrets.conf` on the
|
||||
PostgreSQL server to add:
|
||||
|
||||
```ini
|
||||
s3_region = # region to write to S3; defaults to EC2 host's region
|
||||
s3_backups_key = # aws public key; optional, if access not through role
|
||||
s3_backups_secret_key = # aws secret key; optional, if access not through role
|
||||
s3_backups_bucket = # name of S3 backup bucket
|
||||
```
|
||||
|
||||
1. Run `/home/zulip/deployments/current/scripts/zulip-puppet-apply`.
|
||||
|
||||
Daily full-database backups will be taken at 0200 UTC, and every WAL
|
||||
log will be written to S3 as it is saved by PostgreSQL; by default,
|
||||
this happens every 5 minutes, or every 1G, whichever happens first.
|
||||
If you need always-current backup availability, Zulip also has
|
||||
[built-in database replication support](deployment.md#postgresql-warm-standby).
|
||||
|
||||
You can (and should) monitor that backups are running regularly via
|
||||
the Nagios plugin installed into
|
||||
`/usr/lib/nagios/plugins/zulip_postgresql_backups/check_postgresql_backup`.
|
||||
|
||||
@@ -16,7 +16,7 @@ cd /home/zulip/deployments/current
|
||||
# Start by reading the help
|
||||
./manage.py <command_name> --help
|
||||
|
||||
# Once you've determine this is the command for you, run it!
|
||||
# Once you've determined this is the command for you, run it!
|
||||
./manage.py <command_name> <args>
|
||||
```
|
||||
|
||||
|
||||
@@ -115,7 +115,7 @@ to these terms.
|
||||
We've designed this push notification bouncer service with security
|
||||
and privacy in mind:
|
||||
|
||||
- A central design goal of the the Push Notification Service is to
|
||||
- A central design goal of the Push Notification Service is to
|
||||
avoid any message content being stored or logged by the service,
|
||||
even in error cases.
|
||||
- The Push Notification Service only stores the necessary metadata for
|
||||
@@ -237,7 +237,7 @@ the app stores yourself.
|
||||
If you've done that work, the Zulip server configuration for sending
|
||||
push notifications through the new app is quite straightforward:
|
||||
|
||||
- Create a
|
||||
- Create an
|
||||
[FCM push notifications](https://firebase.google.com/docs/cloud-messaging)
|
||||
key in the Google Developer console and set `android_gcm_api_key` in
|
||||
`/etc/zulip/zulip-secrets.conf` to that key.
|
||||
|
||||
@@ -7,9 +7,9 @@ To run a Zulip server, you will need:
|
||||
- Ubuntu 20.04 Focal
|
||||
- Debian 11 Bullseye
|
||||
- Debian 10 Buster
|
||||
- At least 2GB RAM, and 10GB disk space
|
||||
- If you expect 100+ users: 4GB RAM, and 2 CPUs
|
||||
- If you intend to [upgrade from Git][upgrade-from-git]: 3GB RAM, or
|
||||
- At least 2 GB RAM, and 10 GB disk space
|
||||
- If you expect 100+ users: 4 GB RAM, and 2 CPUs
|
||||
- If you intend to [upgrade from Git][upgrade-from-git]: 3 GB RAM, or
|
||||
2G and at least 1G of swap configured.
|
||||
- A hostname in DNS
|
||||
- Credentials for sending email
|
||||
@@ -59,14 +59,14 @@ sudo apt update
|
||||
#### Hardware specifications
|
||||
|
||||
- CPU and memory: For installations with 100+ users you'll need a
|
||||
minimum of **2 CPUs** and **4GB RAM**. For installations with fewer
|
||||
users, 1 CPU and 2GB RAM is sufficient. We strongly recommend against
|
||||
installing with less than 2GB of RAM, as you will likely experience
|
||||
minimum of **2 CPUs** and **4 GB RAM**. For installations with fewer
|
||||
users, 1 CPU and 2 GB RAM is sufficient. We strongly recommend against
|
||||
installing with less than 2 GB of RAM, as you will likely experience
|
||||
out of memory issues installing dependencies. We recommend against
|
||||
using highly CPU-limited servers like the AWS `t2` style instances
|
||||
for organizations with hundreds of users (active or no).
|
||||
|
||||
- Disk space: You'll need at least 10GB of free disk space for a
|
||||
- Disk space: You'll need at least 10 GB of free disk space for a
|
||||
server with dozens of users. We recommend using an SSD and avoiding
|
||||
cloud storage backends that limit the IOPS per second, since the
|
||||
disk is primarily used for the Zulip database.
|
||||
@@ -104,7 +104,7 @@ on hardware requirements for larger organizations.
|
||||
address as its external hostname (though we don't recommend that
|
||||
configuration).
|
||||
- Zulip supports [running behind a reverse proxy][reverse-proxy].
|
||||
- Zulip configures [Smokescreen, and outgoing HTTP
|
||||
- Zulip configures [Smokescreen, an outgoing HTTP
|
||||
proxy][smokescreen-proxy], to protect against [SSRF attacks][ssrf],
|
||||
which prevents user from making the Zulip server make requests to
|
||||
private resources. If your network has its own outgoing HTTP proxy,
|
||||
@@ -176,11 +176,11 @@ installing Zulip with a dedicated database server.
|
||||
|
||||
- **RAM:** We recommended more RAM for larger installations:
|
||||
|
||||
- With 25+ daily active users, 4GB of RAM.
|
||||
- With 100+ daily active users, 8GB of RAM.
|
||||
- With 400+ daily active users, 16GB of RAM for the Zulip
|
||||
application server, plus 16GB for the database.
|
||||
- With 2000+ daily active users 32GB of RAM, plus 32GB for the
|
||||
- With 25+ daily active users, 4 GB of RAM.
|
||||
- With 100+ daily active users, 8 GB of RAM.
|
||||
- With 400+ daily active users, 16 GB of RAM for the Zulip
|
||||
application server, plus 16 GB for the database.
|
||||
- With 2000+ daily active users 32 GB of RAM, plus 32 GB for the
|
||||
database.
|
||||
- Roughly linear scaling beyond that.
|
||||
|
||||
@@ -195,23 +195,23 @@ installing Zulip with a dedicated database server.
|
||||
|
||||
- **Disk for application server:** We recommend using [the S3 file
|
||||
uploads backend][s3-uploads] to store uploaded files at scale. With
|
||||
the S3 backend configuration, we recommend 50GB of disk for the OS,
|
||||
the S3 backend configuration, we recommend 50 GB of disk for the OS,
|
||||
Zulip software, logs and scratch/free space. Disk needs when
|
||||
storing uploads locally
|
||||
|
||||
- **Disk for database:** SSD disk is highly recommended. For
|
||||
installations where most messages have <100 recipients, 10GB per 1M
|
||||
messages of history is sufficient plus 1GB per 1000 users is
|
||||
installations where most messages have <100 recipients, 10 GB per 1M
|
||||
messages of history is sufficient plus 1 GB per 1000 users is
|
||||
sufficient. If most messages are to public streams with 10K+ users
|
||||
subscribed (like on chat.zulip.org), add 20GB per (1000 user
|
||||
subscribed (like on chat.zulip.org), add 20 GB per (1000 user
|
||||
accounts) per (1M messages to public streams).
|
||||
|
||||
- **Example:** When
|
||||
[the Zulip development community](https://zulip.com/development-community/) server
|
||||
had 12K user accounts (~300 daily actives) and 800K messages of
|
||||
history (400K to public streams), it was a default configuration
|
||||
single-server installation with 16GB of RAM, 4 cores (essentially
|
||||
always idle), and its database was using about 100GB of disk.
|
||||
single-server installation with 16 GB of RAM, 4 cores (essentially
|
||||
always idle), and its database was using about 100 GB of disk.
|
||||
|
||||
- **Disaster recovery:** One can easily run a warm spare application
|
||||
server and a warm spare database (using [PostgreSQL warm standby
|
||||
|
||||
@@ -47,7 +47,6 @@ When everything is running as expected, you will see something like this:
|
||||
```console
|
||||
process-fts-updates RUNNING pid 11392, uptime 19:40:06
|
||||
smokescreen RUNNING pid 3113, uptime 29 days, 21:58:32
|
||||
teleport_node RUNNING pid 15683, uptime 3 days, 13:01:58
|
||||
zulip-django RUNNING pid 11441, uptime 19:39:57
|
||||
zulip-tornado RUNNING pid 11397, uptime 19:40:03
|
||||
zulip_deliver_scheduled_emails RUNNING pid 10289, uptime 19:41:04
|
||||
@@ -77,27 +76,29 @@ isn't running. If you don't see relevant logs in
|
||||
`/etc/supervisor/conf.d/zulip.conf` for details. Logs only make it to
|
||||
`/var/log/zulip/errors.log` once a service has started fully.
|
||||
|
||||
### Restarting services with `supervisorctl restart all`
|
||||
### Restarting services with `supervisorctl restart`
|
||||
|
||||
After you change configuration in `/etc/zulip/settings.py` or fix a
|
||||
misconfiguration, you will often want to restart the Zulip application.
|
||||
You can restart Zulip using:
|
||||
misconfiguration, you will often want to restart the Zulip
|
||||
application. Running `scripts/restart-server` will restart all of
|
||||
Zulip's services; if you want to restart just one of them, you can use
|
||||
`supervisorctl`:
|
||||
|
||||
```bash
|
||||
supervisorctl restart all
|
||||
# You can use this for any service found in `supervisorctl list`
|
||||
supervisorctl restart zulip-django
|
||||
```
|
||||
|
||||
### Stopping services with `supervisorctl stop all`
|
||||
### Stopping services with `supervisorctl stop`
|
||||
|
||||
Similarly, you can stop Zulip using:
|
||||
Similarly, while stopping all of Zulip is best done by running
|
||||
`scripts/stop-server`, you can stop individual Zulip services using:
|
||||
|
||||
```bash
|
||||
supervisorctl stop all
|
||||
# You can use this for any service found in `supervisorctl list`
|
||||
supervisorctl stop zulip-django
|
||||
```
|
||||
|
||||
If you're looking to shut down the server, it is often better to run
|
||||
`./scripts/stop-server`.
|
||||
|
||||
## Troubleshooting services
|
||||
|
||||
The Zulip application uses several major open source services to store
|
||||
|
||||
@@ -174,7 +174,7 @@ after resolving an issue. The most common causes of errors are:
|
||||
minimal RAM for running Zulip can run into out-of-memory issues
|
||||
during the upgrade process (generally `tools/webpack` is the step
|
||||
that fails). You can get past this by shutting down the Zulip
|
||||
server with `supervisorctl stop all` to free up RAM before running
|
||||
server with `./scripts/stop-server` to free up RAM before running
|
||||
the upgrade process.
|
||||
|
||||
Useful logs are available in a few places:
|
||||
@@ -419,7 +419,7 @@ instructions for other supported platforms.
|
||||
to back up the system:
|
||||
|
||||
```bash
|
||||
supervisorctl stop all
|
||||
/home/zulip/deployments/current/scripts/stop-server
|
||||
/home/zulip/deployments/current/manage.py backup --output=/home/zulip/release-upgrade.backup.tar.gz
|
||||
```
|
||||
|
||||
@@ -757,8 +757,8 @@ Many Zulip servers (including chat.zulip.org and zulip.com) upgrade to
|
||||
so, it's important to understand how to happily run a server based on
|
||||
`main`.
|
||||
|
||||
For background, it's backporting arbitrary patches from `main` to an
|
||||
older version requires some care. Common issues include:
|
||||
For background, backporting arbitrary patches from `main` to an older
|
||||
version requires some care. Common issues include:
|
||||
|
||||
- Changes containing database migrations (new files under
|
||||
`*/migrations/`), which includes most new features. We
|
||||
|
||||
@@ -28,6 +28,8 @@ backend. To enable this backend, you need to do the following:
|
||||
|
||||
1. Set `s3_key` and `s3_secret_key` in /etc/zulip/zulip-secrets.conf
|
||||
to be the S3 access and secret keys for the IAM account.
|
||||
Alternately, if your Zulip server runs on an EC2 instance, set the
|
||||
IAM role for the EC2 instance to the role.
|
||||
|
||||
1. Set the `S3_AUTH_UPLOADS_BUCKET` and `S3_AVATAR_BUCKET` settings in
|
||||
`/etc/zulip/settings.py` to be the names of the S3 buckets you
|
||||
|
||||
@@ -18,9 +18,9 @@ The pills will automatically be inserted in before the ".input" in order.
|
||||
## Basic usage
|
||||
|
||||
```js
|
||||
var pill_containter = $("#input_container");
|
||||
var $pill_containter = $("#input_container");
|
||||
var pills = input_pill.create({
|
||||
container: pill_container,
|
||||
$container: $pill_container,
|
||||
create_item_from_text: user_pill.create_item_from_email,
|
||||
get_text_from_item: user_pill.get_email_from_item,
|
||||
});
|
||||
|
||||
@@ -39,10 +39,10 @@ preparing a new release.
|
||||
release, on Ubuntu 20.04.
|
||||
- Repeat until release is ready.
|
||||
- Send around the Paper blog post draft for review.
|
||||
- Move the blog post draft to Ghost. (For a draft in Dropbox Paper,
|
||||
use "··· > Export > Markdown" to get a pretty good markup
|
||||
conversion.) Proofread the post, especially for formatting. Tag
|
||||
the post with "Release announcements" in Ghost.
|
||||
- Move the blog post draft to Ghost:
|
||||
- Use "··· > Export > Markdown" to get a pretty good markdown conversion, then insert that as a Markdown block in Ghost.
|
||||
- Proofread, especially for formatting.
|
||||
- Tag the post with "Release announcements" _first_, then any other tags (e.g. "Security").
|
||||
|
||||
### Executing the release
|
||||
|
||||
@@ -50,6 +50,7 @@ preparing a new release.
|
||||
release branch (for minor releases):
|
||||
- Copy the Markdown release notes for the release into
|
||||
`docs/overview/changelog.md`.
|
||||
- Verify the changelog passes lint, and has the right release date.
|
||||
- _Except minor releases:_ Adjust the `changelog.md` heading to have
|
||||
the stable release series boilerplate.
|
||||
- Update `ZULIP_VERSION` and `LATEST_RELEASE_VERSION` in `version.py`.
|
||||
@@ -67,23 +68,36 @@ preparing a new release.
|
||||
for updating DigitalOcean one-click app image. The action uses the latest release
|
||||
tarball published on `download.zulip.com` for creating the image.
|
||||
|
||||
- Update the [Docker image](https://github.com/zulip/docker-zulip) and
|
||||
do a release of that.
|
||||
- Update the image of DigitalOcean one click app using
|
||||
[Fabric](https://github.com/zulip/marketplace-partners) and publish
|
||||
it to DO marketplace.
|
||||
- Update the [Docker image](https://github.com/zulip/docker-zulip):
|
||||
- Update `ZULIP_GIT_REF` in `Dockerfile`
|
||||
- Update `README.md`
|
||||
- Update the image in `docker-compose.yml`, as well as the `ZULIP_GIT_REF`
|
||||
- Update the image in `kubernetes/zulip-rc.yml`
|
||||
- Build the image: `docker build . -t zulip/docker-zulip:4.11-0 --no-cache`
|
||||
- Also tag it with `latest`: `docker build . -t zulip/docker-zulip:latest`
|
||||
- Push those tags: `docker push zulip/docker-zulip:4.11-0; docker push zulip/docker-zulip:latest`
|
||||
- Update the latest version in [the README in Docker Hub](https://hub.docker.com/repository/docker/zulip/docker-zulip).
|
||||
- Commit the changes and push them to `main`.
|
||||
- Publish the blog post; check the box to "send by email."
|
||||
- Email [zulip-announce](https://groups.google.com/g/zulip-announce),
|
||||
post to [#announce](https://chat.zulip.org/#narrow/stream/1-announce),
|
||||
and [send a tweet](https://twitter.com/zulip).
|
||||
- Announce the release, pointing to the blog post, via:
|
||||
- Email to [zulip-announce](https://groups.google.com/g/zulip-announce)
|
||||
- Message in [#announce](https://chat.zulip.org/#narrow/stream/1-announce)
|
||||
- Tweet from [@zulip](https://twitter.com/zulip).
|
||||
|
||||
### Post-release
|
||||
|
||||
- Update the CI targets in `.github/workflows/production-suite.yml` to
|
||||
include upgrades from the most recent point releases from the last
|
||||
two series -- e.g after releasing 4.8, both `main` and `4.x`
|
||||
should test upgrades from 3.4 and 4.8, and after releasing 5.0 both
|
||||
`main` and `5.x` should test upgrades from 4.8 and 5.0.
|
||||
- The DigitalOcean one-click image will report in an internal channel
|
||||
once it is built, and how to test it. Verify it, then publish it
|
||||
publish it to DigitalOcean marketplace.
|
||||
- Update the CI targets:
|
||||
- _For major releases only:_ In all of the following steps, _also_
|
||||
bump up the series that are being tested.
|
||||
- Update the version in `tools/ci/build-docker-images`
|
||||
- Run `tools/ci/build-docker-images`
|
||||
- Push at least the latest of those, e.g. using `docker push zulip/ci:bullseye-4.11`; update the others at your discretion.
|
||||
- Update the `docker_image` in the `production_upgrade` step of
|
||||
`.github/workflows/production-suite.yml`.
|
||||
- Commit those two changes in a PR.
|
||||
- Following a major release (e.g. 4.0):
|
||||
- Create a release branch (e.g. `4.x`).
|
||||
- On the release branch, update `ZULIP_VERSION` in `version.py` to
|
||||
@@ -95,8 +109,9 @@ preparing a new release.
|
||||
number for future Cloud deployments.
|
||||
- Consider removing a few old releases from ReadTheDocs; we keep about
|
||||
two years of back-versions.
|
||||
- Following a minor release (e.g. 3.2), on the release branch:
|
||||
- Update `ZULIP_VERSION` to the present release with a `+git`
|
||||
suffix, e.g. `3.2+git`.
|
||||
- Update `LATEST_RELEASE_VERSION` with the released version.
|
||||
- Cherry-pick the changelog changes back to `main`.
|
||||
- Following a minor release (e.g. 3.2):
|
||||
- On the release branch, update `ZULIP_VERSION` to the present
|
||||
release with a `+git` suffix, e.g. `3.2+git`.
|
||||
- On main, update `LATEST_RELEASE_VERSION` with the released version.
|
||||
- On main, cherry-pick the changelog changes from the release
|
||||
branch.
|
||||
|
||||
@@ -312,7 +312,7 @@ The code in `static/js/zform.js` renders the form (not
|
||||
shown here) and then sets up a click handler like below:
|
||||
|
||||
```js
|
||||
elem.find('button').on('click', function (e) {
|
||||
$elem.find('button').on('click', function (e) {
|
||||
e.stopPropagation();
|
||||
|
||||
// Grab our index from the markup.
|
||||
|
||||
@@ -8,8 +8,8 @@ const blueslip = require("../zjsunit/zblueslip");
|
||||
const $ = require("../zjsunit/zjquery");
|
||||
const {page_params, user_settings} = require("../zjsunit/zpage_params");
|
||||
|
||||
const window_stub = $.create("window-stub");
|
||||
set_global("to_$", () => window_stub);
|
||||
const $window_stub = $.create("window-stub");
|
||||
set_global("to_$", () => $window_stub);
|
||||
$(window).idle = () => {};
|
||||
|
||||
const _document = {
|
||||
@@ -242,34 +242,34 @@ function simulate_right_column_buddy_list() {
|
||||
};
|
||||
}
|
||||
|
||||
function buddy_list_add(user_id, stub) {
|
||||
if (stub.attr) {
|
||||
stub.attr("data-user-id", user_id);
|
||||
function buddy_list_add(user_id, $stub) {
|
||||
if ($stub.attr) {
|
||||
$stub.attr("data-user-id", user_id);
|
||||
}
|
||||
stub.length = 1;
|
||||
$stub.length = 1;
|
||||
const sel = `li.user_sidebar_entry[data-user-id='${CSS.escape(user_id)}']`;
|
||||
$("#user_presences").set_find_results(sel, stub);
|
||||
$("#user_presences").set_find_results(sel, $stub);
|
||||
}
|
||||
|
||||
test("PM_update_dom_counts", () => {
|
||||
const count = $.create("alice-unread-count");
|
||||
const $count = $.create("alice-unread-count");
|
||||
const pm_key = alice.user_id.toString();
|
||||
const li = $.create("alice stub");
|
||||
buddy_list_add(pm_key, li);
|
||||
li.set_find_results(".unread_count", count);
|
||||
count.set_parents_result("li", li);
|
||||
const $li = $.create("alice stub");
|
||||
buddy_list_add(pm_key, $li);
|
||||
$li.set_find_results(".unread_count", $count);
|
||||
$count.set_parents_result("li", $li);
|
||||
|
||||
const counts = new Map();
|
||||
counts.set(pm_key, 5);
|
||||
li.addClass("user_sidebar_entry");
|
||||
$li.addClass("user_sidebar_entry");
|
||||
|
||||
activity.update_dom_with_unread_counts({pm_count: counts});
|
||||
assert.equal(count.text(), "5");
|
||||
assert.equal($count.text(), "5");
|
||||
|
||||
counts.set(pm_key, 0);
|
||||
|
||||
activity.update_dom_with_unread_counts({pm_count: counts});
|
||||
assert.equal(count.text(), "");
|
||||
assert.equal($count.text(), "");
|
||||
});
|
||||
|
||||
test("handlers", ({override, override_rewire, mock_template}) => {
|
||||
@@ -289,9 +289,9 @@ test("handlers", ({override, override_rewire, mock_template}) => {
|
||||
|
||||
// This is kind of weak coverage; we are mostly making sure that
|
||||
// keys and clicks got mapped to functions that don't crash.
|
||||
let me_li;
|
||||
let alice_li;
|
||||
let fred_li;
|
||||
let $me_li;
|
||||
let $alice_li;
|
||||
let $fred_li;
|
||||
|
||||
let narrowed;
|
||||
|
||||
@@ -307,13 +307,13 @@ test("handlers", ({override, override_rewire, mock_template}) => {
|
||||
});
|
||||
activity.set_cursor_and_filter();
|
||||
|
||||
me_li = $.create("me stub");
|
||||
alice_li = $.create("alice stub");
|
||||
fred_li = $.create("fred stub");
|
||||
$me_li = $.create("me stub");
|
||||
$alice_li = $.create("alice stub");
|
||||
$fred_li = $.create("fred stub");
|
||||
|
||||
buddy_list_add(me.user_id, me_li);
|
||||
buddy_list_add(alice.user_id, alice_li);
|
||||
buddy_list_add(fred.user_id, fred_li);
|
||||
buddy_list_add(me.user_id, $me_li);
|
||||
buddy_list_add(alice.user_id, $alice_li);
|
||||
buddy_list_add(fred.user_id, $fred_li);
|
||||
}
|
||||
|
||||
(function test_filter_keys() {
|
||||
@@ -364,7 +364,7 @@ test("handlers", ({override, override_rewire, mock_template}) => {
|
||||
// We wire up the click handler in click_handlers.js,
|
||||
// so this just tests the called function.
|
||||
narrowed = false;
|
||||
activity.narrow_for_user({li: alice_li});
|
||||
activity.narrow_for_user({$li: $alice_li});
|
||||
assert.ok(narrowed);
|
||||
})();
|
||||
|
||||
@@ -420,7 +420,7 @@ test("first/prev/next", ({override, mock_template}) => {
|
||||
assert.equal(buddy_list.prev_key(alice.user_id), undefined);
|
||||
assert.equal(buddy_list.next_key(alice.user_id), undefined);
|
||||
|
||||
override(buddy_list.container, "append", () => {});
|
||||
override(buddy_list.$container, "append", () => {});
|
||||
|
||||
activity.redraw_user(alice.user_id);
|
||||
activity.redraw_user(fred.user_id);
|
||||
@@ -457,7 +457,7 @@ test("insert_one_user_into_empty_list", ({override, mock_template}) => {
|
||||
override(padded_widget, "update_padding", () => {});
|
||||
|
||||
let appended_html;
|
||||
override(buddy_list.container, "append", (html) => {
|
||||
override(buddy_list.$container, "append", (html) => {
|
||||
appended_html = html;
|
||||
});
|
||||
|
||||
@@ -470,7 +470,7 @@ test("insert_alice_then_fred", ({override, mock_template}) => {
|
||||
mock_template("user_presence_row.hbs", true, (data, html) => html);
|
||||
|
||||
let appended_html;
|
||||
override(buddy_list.container, "append", (html) => {
|
||||
override(buddy_list.$container, "append", (html) => {
|
||||
appended_html = html;
|
||||
});
|
||||
override(padded_widget, "update_padding", () => {});
|
||||
@@ -488,7 +488,7 @@ test("insert_fred_then_alice_then_rename", ({override, mock_template}) => {
|
||||
mock_template("user_presence_row.hbs", true, (data, html) => html);
|
||||
|
||||
let appended_html;
|
||||
override(buddy_list.container, "append", (html) => {
|
||||
override(buddy_list.$container, "append", (html) => {
|
||||
appended_html = html;
|
||||
});
|
||||
override(padded_widget, "update_padding", () => {});
|
||||
@@ -497,16 +497,16 @@ test("insert_fred_then_alice_then_rename", ({override, mock_template}) => {
|
||||
assert.ok(appended_html.indexOf('data-user-id="2"') > 0);
|
||||
assert.ok(appended_html.indexOf("user_circle_green") > 0);
|
||||
|
||||
const fred_stub = $.create("fred-first");
|
||||
buddy_list_add(fred.user_id, fred_stub);
|
||||
const $fred_stub = $.create("fred-first");
|
||||
buddy_list_add(fred.user_id, $fred_stub);
|
||||
|
||||
let inserted_html;
|
||||
fred_stub.before = (html) => {
|
||||
$fred_stub.before = (html) => {
|
||||
inserted_html = html;
|
||||
};
|
||||
|
||||
let fred_removed;
|
||||
fred_stub.remove = () => {
|
||||
$fred_stub.remove = () => {
|
||||
fred_removed = true;
|
||||
};
|
||||
|
||||
@@ -522,10 +522,10 @@ test("insert_fred_then_alice_then_rename", ({override, mock_template}) => {
|
||||
};
|
||||
people.add_active_user(fred_with_new_name);
|
||||
|
||||
const alice_stub = $.create("alice-first");
|
||||
buddy_list_add(alice.user_id, alice_stub);
|
||||
const $alice_stub = $.create("alice-first");
|
||||
buddy_list_add(alice.user_id, $alice_stub);
|
||||
|
||||
alice_stub.before = (html) => {
|
||||
$alice_stub.before = (html) => {
|
||||
inserted_html = html;
|
||||
};
|
||||
|
||||
@@ -541,8 +541,8 @@ test("insert_unfiltered_user_with_filter", () => {
|
||||
// This test only tests that we do not explode when
|
||||
// try to insert Fred into a list where he does not
|
||||
// match the search filter.
|
||||
const user_filter = $(".user-list-filter");
|
||||
user_filter.val("do-not-match-filter");
|
||||
const $user_filter = $(".user-list-filter");
|
||||
$user_filter.val("do-not-match-filter");
|
||||
activity.redraw_user(fred.user_id);
|
||||
});
|
||||
|
||||
@@ -579,8 +579,8 @@ test("update_presence_info", ({override, override_rewire}) => {
|
||||
|
||||
override_rewire(buddy_data, "matches_filter", () => true);
|
||||
|
||||
const alice_li = $.create("alice stub");
|
||||
buddy_list_add(alice.user_id, alice_li);
|
||||
const $alice_li = $.create("alice stub");
|
||||
buddy_list_add(alice.user_id, $alice_li);
|
||||
|
||||
let inserted;
|
||||
override(buddy_list, "insert_or_move", () => {
|
||||
@@ -613,8 +613,8 @@ test("initialize", ({override, mock_template}) => {
|
||||
|
||||
function clear() {
|
||||
$.clear_all_elements();
|
||||
buddy_list.container = $("#user_presences");
|
||||
buddy_list.container.append = () => {};
|
||||
buddy_list.$container = $("#user_presences");
|
||||
buddy_list.$container.append = () => {};
|
||||
clear_buddy_list();
|
||||
page_params.presences = {};
|
||||
}
|
||||
|
||||
@@ -50,31 +50,31 @@ run_test("add_alert_word", ({override_rewire}) => {
|
||||
|
||||
alert_words_ui.set_up_alert_words();
|
||||
|
||||
const create_form = $("#create_alert_word_form");
|
||||
const add_func = create_form.get_on_handler("click", "#create_alert_word_button");
|
||||
const $create_form = $("#create_alert_word_form");
|
||||
const add_func = $create_form.get_on_handler("click", "#create_alert_word_button");
|
||||
|
||||
const new_alert_word = $("#create_alert_word_name");
|
||||
const alert_word_status = $("#alert_word_status");
|
||||
const alert_word_status_text = $(".alert_word_status_text");
|
||||
alert_word_status.set_find_results(".alert_word_status_text", alert_word_status_text);
|
||||
const $new_alert_word = $("#create_alert_word_name");
|
||||
const $alert_word_status = $("#alert_word_status");
|
||||
const $alert_word_status_text = $(".alert_word_status_text");
|
||||
$alert_word_status.set_find_results(".alert_word_status_text", $alert_word_status_text);
|
||||
|
||||
// add '' as alert word
|
||||
add_func();
|
||||
assert.equal(new_alert_word.val(), "");
|
||||
assert.ok(alert_word_status.hasClass("alert-danger"));
|
||||
assert.equal(alert_word_status_text.text(), "translated: Alert word can't be empty!");
|
||||
assert.ok(alert_word_status.visible());
|
||||
assert.equal($new_alert_word.val(), "");
|
||||
assert.ok($alert_word_status.hasClass("alert-danger"));
|
||||
assert.equal($alert_word_status_text.text(), "translated: Alert word can't be empty!");
|
||||
assert.ok($alert_word_status.visible());
|
||||
|
||||
// add 'foo' as alert word (existing word)
|
||||
new_alert_word.val("foo");
|
||||
$new_alert_word.val("foo");
|
||||
|
||||
add_func();
|
||||
assert.ok(alert_word_status.hasClass("alert-danger"));
|
||||
assert.equal(alert_word_status_text.text(), "translated: Alert word already exists!");
|
||||
assert.ok(alert_word_status.visible());
|
||||
assert.ok($alert_word_status.hasClass("alert-danger"));
|
||||
assert.equal($alert_word_status_text.text(), "translated: Alert word already exists!");
|
||||
assert.ok($alert_word_status.visible());
|
||||
|
||||
// add 'zot' as alert word (new word)
|
||||
new_alert_word.val("zot");
|
||||
$new_alert_word.val("zot");
|
||||
|
||||
let success_func;
|
||||
let fail_func;
|
||||
@@ -89,26 +89,29 @@ run_test("add_alert_word", ({override_rewire}) => {
|
||||
|
||||
// test failure
|
||||
fail_func();
|
||||
assert.ok(alert_word_status.hasClass("alert-danger"));
|
||||
assert.equal(alert_word_status_text.text(), "translated: Error adding alert word!");
|
||||
assert.ok(alert_word_status.visible());
|
||||
assert.ok($alert_word_status.hasClass("alert-danger"));
|
||||
assert.equal($alert_word_status_text.text(), "translated: Error adding alert word!");
|
||||
assert.ok($alert_word_status.visible());
|
||||
|
||||
// test success
|
||||
success_func();
|
||||
assert.ok(alert_word_status.hasClass("alert-success"));
|
||||
assert.equal(alert_word_status_text.text(), 'translated: Alert word "zot" added successfully!');
|
||||
assert.ok(alert_word_status.visible());
|
||||
assert.ok($alert_word_status.hasClass("alert-success"));
|
||||
assert.equal(
|
||||
$alert_word_status_text.text(),
|
||||
'translated: Alert word "zot" added successfully!',
|
||||
);
|
||||
assert.ok($alert_word_status.visible());
|
||||
});
|
||||
|
||||
run_test("add_alert_word_keypress", ({override_rewire}) => {
|
||||
override_rewire(alert_words_ui, "rerender_alert_words_ui", () => {});
|
||||
alert_words_ui.set_up_alert_words();
|
||||
|
||||
const create_form = $("#create_alert_word_form");
|
||||
const keypress_func = create_form.get_on_handler("keypress", "#create_alert_word_name");
|
||||
const $create_form = $("#create_alert_word_form");
|
||||
const keypress_func = $create_form.get_on_handler("keypress", "#create_alert_word_name");
|
||||
|
||||
const new_alert_word = $("#create_alert_word_name");
|
||||
new_alert_word.val("zot");
|
||||
const $new_alert_word = $("#create_alert_word_name");
|
||||
$new_alert_word.val("zot");
|
||||
|
||||
const event = {
|
||||
preventDefault: () => {},
|
||||
@@ -130,16 +133,16 @@ run_test("remove_alert_word", ({override_rewire}) => {
|
||||
override_rewire(alert_words_ui, "rerender_alert_words_ui", () => {});
|
||||
alert_words_ui.set_up_alert_words();
|
||||
|
||||
const word_list = $("#alert-words-table");
|
||||
const remove_func = word_list.get_on_handler("click", ".remove-alert-word");
|
||||
const $word_list = $("#alert-words-table");
|
||||
const remove_func = $word_list.get_on_handler("click", ".remove-alert-word");
|
||||
|
||||
const remove_alert_word = $(".remove-alert-word");
|
||||
const list_item = $("tr.alert-word-item");
|
||||
const val_item = $("span.value");
|
||||
val_item.text($t({defaultMessage: "zot"}));
|
||||
const $remove_alert_word = $(".remove-alert-word");
|
||||
const $list_item = $("tr.alert-word-item");
|
||||
const $val_item = $("span.value");
|
||||
$val_item.text($t({defaultMessage: "zot"}));
|
||||
|
||||
remove_alert_word.set_parents_result("tr", list_item);
|
||||
list_item.set_find_results(".value", val_item);
|
||||
$remove_alert_word.set_parents_result("tr", $list_item);
|
||||
$list_item.set_find_results(".value", $val_item);
|
||||
|
||||
const event = {
|
||||
currentTarget: ".remove-alert-word",
|
||||
@@ -156,42 +159,42 @@ run_test("remove_alert_word", ({override_rewire}) => {
|
||||
|
||||
remove_func(event);
|
||||
|
||||
const alert_word_status = $("#alert_word_status");
|
||||
const alert_word_status_text = $(".alert_word_status_text");
|
||||
alert_word_status.set_find_results(".alert_word_status_text", alert_word_status_text);
|
||||
const $alert_word_status = $("#alert_word_status");
|
||||
const $alert_word_status_text = $(".alert_word_status_text");
|
||||
$alert_word_status.set_find_results(".alert_word_status_text", $alert_word_status_text);
|
||||
|
||||
// test failure
|
||||
fail_func();
|
||||
assert.ok(alert_word_status.hasClass("alert-danger"));
|
||||
assert.equal(alert_word_status_text.text(), "translated: Error removing alert word!");
|
||||
assert.ok(alert_word_status.visible());
|
||||
assert.ok($alert_word_status.hasClass("alert-danger"));
|
||||
assert.equal($alert_word_status_text.text(), "translated: Error removing alert word!");
|
||||
assert.ok($alert_word_status.visible());
|
||||
|
||||
// test success
|
||||
success_func();
|
||||
assert.ok(alert_word_status.hasClass("alert-success"));
|
||||
assert.equal(alert_word_status_text.text(), "translated: Alert word removed successfully!");
|
||||
assert.ok(alert_word_status.visible());
|
||||
assert.ok($alert_word_status.hasClass("alert-success"));
|
||||
assert.equal($alert_word_status_text.text(), "translated: Alert word removed successfully!");
|
||||
assert.ok($alert_word_status.visible());
|
||||
});
|
||||
|
||||
run_test("close_status_message", ({override_rewire}) => {
|
||||
override_rewire(alert_words_ui, "rerender_alert_words_ui", () => {});
|
||||
alert_words_ui.set_up_alert_words();
|
||||
|
||||
const alert_word_settings = $("#alert-word-settings");
|
||||
const close = alert_word_settings.get_on_handler("click", ".close-alert-word-status");
|
||||
const $alert_word_settings = $("#alert-word-settings");
|
||||
const close = $alert_word_settings.get_on_handler("click", ".close-alert-word-status");
|
||||
|
||||
const alert = $(".alert");
|
||||
const close_btn = $(".close-alert-word-status");
|
||||
close_btn.set_parents_result(".alert", alert);
|
||||
const $alert = $(".alert");
|
||||
const $close_btn = $(".close-alert-word-status");
|
||||
$close_btn.set_parents_result(".alert", $alert);
|
||||
|
||||
alert.show();
|
||||
$alert.show();
|
||||
|
||||
const event = {
|
||||
preventDefault: () => {},
|
||||
currentTarget: ".close-alert-word-status",
|
||||
};
|
||||
|
||||
assert.ok(alert.visible());
|
||||
assert.ok($alert.visible());
|
||||
close(event);
|
||||
assert.ok(!alert.visible());
|
||||
assert.ok(!$alert.visible());
|
||||
});
|
||||
|
||||
@@ -52,8 +52,8 @@ run_test("create_ajax_request", ({override}) => {
|
||||
make_indicator: 0,
|
||||
};
|
||||
|
||||
loading.make_indicator = (loading_indicator, config) => {
|
||||
assert.equal(loading_indicator.selector, form_loading_indicator);
|
||||
loading.make_indicator = ($loading_indicator, config) => {
|
||||
assert.equal($loading_indicator.selector, form_loading_indicator);
|
||||
assert.equal(config.text, "Processing ...");
|
||||
assert.equal(config.abs_positioned, true);
|
||||
state.make_indicator += 1;
|
||||
|
||||
@@ -39,18 +39,18 @@ people.add_active_user(alice);
|
||||
run_test("get_items", () => {
|
||||
const buddy_list = new BuddyList();
|
||||
|
||||
// We don't make alice_li an actual jQuery stub,
|
||||
// We don't make $alice_li an actual jQuery stub,
|
||||
// because our test only cares that it comes
|
||||
// back from get_items.
|
||||
const alice_li = "alice stub";
|
||||
const $alice_li = "alice stub";
|
||||
const sel = "li.user_sidebar_entry";
|
||||
const container = $.create("get_items container", {
|
||||
children: [{to_$: () => alice_li}],
|
||||
const $container = $.create("get_items container", {
|
||||
children: [{to_$: () => $alice_li}],
|
||||
});
|
||||
buddy_list.container.set_find_results(sel, container);
|
||||
buddy_list.$container.set_find_results(sel, $container);
|
||||
|
||||
const items = buddy_list.get_items();
|
||||
assert.deepEqual(items, [alice_li]);
|
||||
assert.deepEqual(items, [$alice_li]);
|
||||
});
|
||||
|
||||
run_test("basics", ({override}) => {
|
||||
@@ -83,19 +83,19 @@ run_test("basics", ({override}) => {
|
||||
});
|
||||
assert.ok(appended);
|
||||
|
||||
const alice_li = {length: 1};
|
||||
const $alice_li = {length: 1};
|
||||
|
||||
override(buddy_list, "get_li_from_key", (opts) => {
|
||||
const key = opts.key;
|
||||
|
||||
assert.equal(key, alice.user_id);
|
||||
return alice_li;
|
||||
return $alice_li;
|
||||
});
|
||||
|
||||
const li = buddy_list.find_li({
|
||||
const $li = buddy_list.find_li({
|
||||
key: alice.user_id,
|
||||
});
|
||||
assert.equal(li, alice_li);
|
||||
assert.equal($li, $alice_li);
|
||||
});
|
||||
|
||||
run_test("big_list", ({override}) => {
|
||||
@@ -163,11 +163,11 @@ run_test("find_li w/force_render", ({override}) => {
|
||||
// key is not already rendered in DOM, then the
|
||||
// widget will call show_key to force-render it.
|
||||
const key = "999";
|
||||
const stub_li = {length: 0};
|
||||
const $stub_li = {length: 0};
|
||||
|
||||
override(buddy_list, "get_li_from_key", (opts) => {
|
||||
assert.equal(opts.key, key);
|
||||
return stub_li;
|
||||
return $stub_li;
|
||||
});
|
||||
|
||||
buddy_list.keys = ["foo", "bar", key, "baz"];
|
||||
@@ -179,18 +179,18 @@ run_test("find_li w/force_render", ({override}) => {
|
||||
shown = true;
|
||||
});
|
||||
|
||||
const empty_li = buddy_list.find_li({
|
||||
const $empty_li = buddy_list.find_li({
|
||||
key,
|
||||
});
|
||||
assert.equal(empty_li, stub_li);
|
||||
assert.equal($empty_li, $stub_li);
|
||||
assert.ok(!shown);
|
||||
|
||||
const li = buddy_list.find_li({
|
||||
const $li = buddy_list.find_li({
|
||||
key,
|
||||
force_render: true,
|
||||
});
|
||||
|
||||
assert.equal(li, stub_li);
|
||||
assert.equal($li, $stub_li);
|
||||
assert.ok(shown);
|
||||
});
|
||||
|
||||
@@ -198,12 +198,12 @@ run_test("find_li w/bad key", ({override}) => {
|
||||
const buddy_list = new BuddyList();
|
||||
override(buddy_list, "get_li_from_key", () => ({length: 0}));
|
||||
|
||||
const undefined_li = buddy_list.find_li({
|
||||
const $undefined_li = buddy_list.find_li({
|
||||
key: "not-there",
|
||||
force_render: true,
|
||||
});
|
||||
|
||||
assert.deepEqual(undefined_li, []);
|
||||
assert.deepEqual($undefined_li, []);
|
||||
});
|
||||
|
||||
run_test("scrolling", ({override}) => {
|
||||
|
||||
@@ -39,41 +39,41 @@ run_test("phrase_match", () => {
|
||||
run_test("copy_data_attribute_value", ({override}) => {
|
||||
const admin_emails_val = "iago@zulip.com";
|
||||
|
||||
const input = $.create("input");
|
||||
const $input = $.create("input");
|
||||
|
||||
let removed;
|
||||
input.remove = () => {
|
||||
$input.remove = () => {
|
||||
removed = true;
|
||||
};
|
||||
|
||||
override(document, "createElement", () => input);
|
||||
override(document, "createElement", () => $input);
|
||||
override(document, "execCommand", noop);
|
||||
|
||||
$("body").append = noop;
|
||||
$(input).val = (arg) => {
|
||||
$($input).val = (arg) => {
|
||||
assert.equal(arg, admin_emails_val);
|
||||
return {
|
||||
trigger: noop,
|
||||
};
|
||||
};
|
||||
|
||||
const elem = {};
|
||||
const $elem = {};
|
||||
let faded_in = false;
|
||||
let faded_out = false;
|
||||
|
||||
elem.data = (key) => {
|
||||
$elem.data = (key) => {
|
||||
assert.equal(key, "admin-emails");
|
||||
return admin_emails_val;
|
||||
};
|
||||
elem.fadeOut = (val) => {
|
||||
$elem.fadeOut = (val) => {
|
||||
assert.equal(val, 250);
|
||||
faded_out = true;
|
||||
};
|
||||
elem.fadeIn = (val) => {
|
||||
$elem.fadeIn = (val) => {
|
||||
assert.equal(val, 1000);
|
||||
faded_in = true;
|
||||
};
|
||||
common.copy_data_attribute_value(elem, "admin-emails");
|
||||
common.copy_data_attribute_value($elem, "admin-emails");
|
||||
assert.ok(removed);
|
||||
assert.ok(faded_in);
|
||||
assert.ok(faded_out);
|
||||
@@ -111,17 +111,17 @@ run_test("adjust_mac_shortcuts mac", ({override_rewire}) => {
|
||||
|
||||
for (const [old_key, mac_key] of keys_to_test_mac) {
|
||||
const test_item = {};
|
||||
const stub = $.create("hotkey_" + key_no);
|
||||
stub.text(old_key);
|
||||
assert.equal(stub.hasClass("mac-cmd-key"), false);
|
||||
test_item.stub = stub;
|
||||
const $stub = $.create("hotkey_" + key_no);
|
||||
$stub.text(old_key);
|
||||
assert.equal($stub.hasClass("mac-cmd-key"), false);
|
||||
test_item.$stub = $stub;
|
||||
test_item.mac_key = mac_key;
|
||||
test_item.is_cmd_key = old_key.includes("Ctrl");
|
||||
test_items.push(test_item);
|
||||
key_no += 1;
|
||||
}
|
||||
|
||||
const children = test_items.map((test_item) => ({to_$: () => test_item.stub}));
|
||||
const children = test_items.map((test_item) => ({to_$: () => test_item.$stub}));
|
||||
|
||||
$.create(".markdown_content", {children});
|
||||
|
||||
@@ -129,8 +129,8 @@ run_test("adjust_mac_shortcuts mac", ({override_rewire}) => {
|
||||
common.adjust_mac_shortcuts(".markdown_content", require_cmd);
|
||||
|
||||
for (const test_item of test_items) {
|
||||
assert.equal(test_item.stub.hasClass("mac-cmd-key"), test_item.is_cmd_key);
|
||||
assert.equal(test_item.stub.text(), test_item.mac_key);
|
||||
assert.equal(test_item.$stub.hasClass("mac-cmd-key"), test_item.is_cmd_key);
|
||||
assert.equal(test_item.$stub.text(), test_item.mac_key);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -10,35 +10,35 @@ const blueslip = require("../zjsunit/zblueslip");
|
||||
let env;
|
||||
|
||||
function make_tab(i) {
|
||||
const self = {};
|
||||
const $self = {};
|
||||
|
||||
assert.equal(env.tabs.length, i);
|
||||
|
||||
self.stub = true;
|
||||
self.class = [];
|
||||
$self.stub = true;
|
||||
$self.class = [];
|
||||
|
||||
self.addClass = (c) => {
|
||||
self.class += " " + c;
|
||||
const tokens = self.class.trim().split(/ +/);
|
||||
self.class = Array.from(new Set(tokens)).join(" ");
|
||||
$self.addClass = (c) => {
|
||||
$self.class += " " + c;
|
||||
const tokens = $self.class.trim().split(/ +/);
|
||||
$self.class = Array.from(new Set(tokens)).join(" ");
|
||||
};
|
||||
|
||||
self.removeClass = (c) => {
|
||||
const tokens = self.class.trim().split(/ +/);
|
||||
self.class = tokens.filter((token) => token !== c).join(" ");
|
||||
$self.removeClass = (c) => {
|
||||
const tokens = $self.class.trim().split(/ +/);
|
||||
$self.class = tokens.filter((token) => token !== c).join(" ");
|
||||
};
|
||||
|
||||
self.hasClass = (c) => {
|
||||
const tokens = self.class.trim().split(/ +/);
|
||||
$self.hasClass = (c) => {
|
||||
const tokens = $self.class.trim().split(/ +/);
|
||||
return tokens.includes(c);
|
||||
};
|
||||
|
||||
self.data = (name) => {
|
||||
$self.data = (name) => {
|
||||
assert.equal(name, "tab-id");
|
||||
return i;
|
||||
};
|
||||
|
||||
self.text = (text) => {
|
||||
$self.text = (text) => {
|
||||
assert.equal(
|
||||
text,
|
||||
[
|
||||
@@ -49,23 +49,23 @@ function make_tab(i) {
|
||||
);
|
||||
};
|
||||
|
||||
self.trigger = (type) => {
|
||||
$self.trigger = (type) => {
|
||||
if (type === "focus") {
|
||||
env.focused_tab = i;
|
||||
}
|
||||
};
|
||||
|
||||
env.tabs.push(self);
|
||||
env.tabs.push($self);
|
||||
|
||||
return self;
|
||||
return $self;
|
||||
}
|
||||
|
||||
const ind_tab = (function () {
|
||||
const self = {};
|
||||
const $self = {};
|
||||
|
||||
self.stub = true;
|
||||
$self.stub = true;
|
||||
|
||||
self.on = (name, f) => {
|
||||
$self.on = (name, f) => {
|
||||
if (name === "click") {
|
||||
env.click_f = f;
|
||||
} else if (name === "keydown") {
|
||||
@@ -73,36 +73,36 @@ const ind_tab = (function () {
|
||||
}
|
||||
};
|
||||
|
||||
self.removeClass = (c) => {
|
||||
for (const tab of env.tabs) {
|
||||
tab.removeClass(c);
|
||||
$self.removeClass = (c) => {
|
||||
for (const $tab of env.tabs) {
|
||||
$tab.removeClass(c);
|
||||
}
|
||||
};
|
||||
|
||||
self.eq = (idx) => env.tabs[idx];
|
||||
$self.eq = (idx) => env.tabs[idx];
|
||||
|
||||
return self;
|
||||
return $self;
|
||||
})();
|
||||
|
||||
function make_switcher() {
|
||||
const self = {};
|
||||
const $self = {};
|
||||
|
||||
self.stub = true;
|
||||
$self.stub = true;
|
||||
|
||||
self.children = [];
|
||||
$self.children = [];
|
||||
|
||||
self.classList = new Set();
|
||||
$self.classList = new Set();
|
||||
|
||||
self.append = (child) => {
|
||||
self.children.push(child);
|
||||
$self.append = (child) => {
|
||||
$self.children.push(child);
|
||||
};
|
||||
|
||||
self.addClass = (c) => {
|
||||
self.classList.add(c);
|
||||
self.addedClass = c;
|
||||
$self.addClass = (c) => {
|
||||
$self.classList.add(c);
|
||||
$self.addedClass = c;
|
||||
};
|
||||
|
||||
self.find = (sel) => {
|
||||
$self.find = (sel) => {
|
||||
switch (sel) {
|
||||
case ".ind-tab":
|
||||
return ind_tab;
|
||||
@@ -111,7 +111,7 @@ function make_switcher() {
|
||||
}
|
||||
};
|
||||
|
||||
return self;
|
||||
return $self;
|
||||
}
|
||||
|
||||
mock_jquery((sel, attributes) => {
|
||||
@@ -121,11 +121,10 @@ mock_jquery((sel, attributes) => {
|
||||
}
|
||||
|
||||
switch (sel) {
|
||||
case "<div class='tab-switcher'></div>":
|
||||
return env.switcher;
|
||||
case "<div class='tab-switcher stream_sorter_toggle'></div>":
|
||||
return env.switcher;
|
||||
case "<div>": {
|
||||
if (attributes.class === "tab-switcher") {
|
||||
return env.switcher;
|
||||
}
|
||||
const tab_id = attributes["data-tab-id"];
|
||||
assert.deepEqual(
|
||||
attributes,
|
||||
|
||||
@@ -285,8 +285,8 @@ test_ui("enter_with_preview_open", ({override, override_rewire}) => {
|
||||
override(reminder, "is_deferred_delivery", () => false);
|
||||
override(document, "to_$", () => $("document-stub"));
|
||||
let show_button_spinner_called = false;
|
||||
override(loading, "show_button_spinner", (spinner) => {
|
||||
assert.equal(spinner.selector, "#compose-send-button .loader");
|
||||
override(loading, "show_button_spinner", ($spinner) => {
|
||||
assert.equal($spinner.selector, "#compose-send-button .loader");
|
||||
show_button_spinner_called = true;
|
||||
});
|
||||
|
||||
@@ -333,8 +333,8 @@ test_ui("finish", ({override, override_rewire}) => {
|
||||
override(reminder, "is_deferred_delivery", () => false);
|
||||
override(document, "to_$", () => $("document-stub"));
|
||||
let show_button_spinner_called = false;
|
||||
override(loading, "show_button_spinner", (spinner) => {
|
||||
assert.equal(spinner.selector, "#compose-send-button .loader");
|
||||
override(loading, "show_button_spinner", ($spinner) => {
|
||||
assert.equal($spinner.selector, "#compose-send-button .loader");
|
||||
show_button_spinner_called = true;
|
||||
});
|
||||
|
||||
@@ -552,27 +552,28 @@ test_ui("on_events", ({override, override_rewire}) => {
|
||||
override(rendered_markdown, "update_elements", () => {});
|
||||
|
||||
function setup_parents_and_mock_remove(container_sel, target_sel, parent) {
|
||||
const container = $.create("fake " + container_sel);
|
||||
const $container = $.create("fake " + container_sel);
|
||||
let container_removed = false;
|
||||
|
||||
container.remove = () => {
|
||||
$container.remove = () => {
|
||||
container_removed = true;
|
||||
};
|
||||
|
||||
const target = $.create("fake click target (" + target_sel + ")");
|
||||
const $target = $.create("fake click target (" + target_sel + ")");
|
||||
|
||||
target.set_parents_result(parent, container);
|
||||
$target.set_parents_result(parent, $container);
|
||||
|
||||
const event = {
|
||||
preventDefault: noop,
|
||||
stopPropagation: noop,
|
||||
target,
|
||||
// FIXME: event.target should not be a jQuery object
|
||||
target: $target,
|
||||
};
|
||||
|
||||
const helper = {
|
||||
event,
|
||||
container,
|
||||
target,
|
||||
$container,
|
||||
$target,
|
||||
container_was_removed: () => container_removed,
|
||||
};
|
||||
|
||||
@@ -633,7 +634,7 @@ test_ui("on_events", ({override, override_rewire}) => {
|
||||
".compose_invite_user",
|
||||
);
|
||||
|
||||
helper.container.data = (field) => {
|
||||
helper.$container.data = (field) => {
|
||||
if (field === "user-id") {
|
||||
return "34";
|
||||
}
|
||||
@@ -642,7 +643,7 @@ test_ui("on_events", ({override, override_rewire}) => {
|
||||
}
|
||||
throw new Error(`Unknown field ${field}`);
|
||||
};
|
||||
helper.target.prop("disabled", false);
|
||||
helper.$target.prop("disabled", false);
|
||||
|
||||
// !sub will result in true here and we check the success code path.
|
||||
stream_data.add_sub(subscription);
|
||||
@@ -814,8 +815,8 @@ test_ui("on_events", ({override, override_rewire}) => {
|
||||
|
||||
function test(func, param) {
|
||||
let destroy_indicator_called = false;
|
||||
override(loading, "destroy_indicator", (spinner) => {
|
||||
assert.equal(spinner, $("#compose .markdown_preview_spinner"));
|
||||
override(loading, "destroy_indicator", ($spinner) => {
|
||||
assert.equal($spinner, $("#compose .markdown_preview_spinner"));
|
||||
destroy_indicator_called = true;
|
||||
});
|
||||
setup_mock_markdown_contains_backend_only_syntax(current_message, true);
|
||||
@@ -852,8 +853,8 @@ test_ui("on_events", ({override, override_rewire}) => {
|
||||
setup_mock_markdown_contains_backend_only_syntax("```foobarfoobar```", true);
|
||||
setup_mock_markdown_is_status_message("```foobarfoobar```", false);
|
||||
|
||||
override(loading, "make_indicator", (spinner) => {
|
||||
assert.equal(spinner.selector, "#compose .markdown_preview_spinner");
|
||||
override(loading, "make_indicator", ($spinner) => {
|
||||
assert.equal($spinner.selector, "#compose .markdown_preview_spinner");
|
||||
make_indicator_called = true;
|
||||
});
|
||||
|
||||
|
||||
@@ -43,9 +43,9 @@ run_test("pills", ({override}) => {
|
||||
|
||||
people.get_realm_users = () => [iago, othello, hamlet];
|
||||
|
||||
const recipient_stub = $("#private_message_recipient");
|
||||
const $recipient_stub = $("#private_message_recipient");
|
||||
const pill_container_stub = "pill-container";
|
||||
recipient_stub.set_parent(pill_container_stub);
|
||||
$recipient_stub.set_parent(pill_container_stub);
|
||||
let create_item_handler;
|
||||
|
||||
const all_pills = new Map();
|
||||
@@ -132,7 +132,7 @@ run_test("pills", ({override}) => {
|
||||
}
|
||||
|
||||
function input_pill_stub(opts) {
|
||||
assert.equal(opts.container, pill_container_stub);
|
||||
assert.equal(opts.$container, pill_container_stub);
|
||||
create_item_handler = opts.create_item_from_text;
|
||||
assert.ok(create_item_handler);
|
||||
return pills;
|
||||
|
||||
@@ -46,48 +46,48 @@ people.add_active_user(bob);
|
||||
|
||||
function make_textbox(s) {
|
||||
// Simulate a jQuery textbox for testing purposes.
|
||||
const widget = {};
|
||||
const $widget = {};
|
||||
|
||||
widget.s = s;
|
||||
widget.focused = false;
|
||||
$widget.s = s;
|
||||
$widget.focused = false;
|
||||
|
||||
widget.caret = function (arg) {
|
||||
$widget.caret = function (arg) {
|
||||
if (typeof arg === "number") {
|
||||
widget.pos = arg;
|
||||
$widget.pos = arg;
|
||||
return this;
|
||||
}
|
||||
|
||||
if (arg) {
|
||||
widget.insert_pos = widget.pos;
|
||||
widget.insert_text = arg;
|
||||
const before = widget.s.slice(0, widget.pos);
|
||||
const after = widget.s.slice(widget.pos);
|
||||
widget.s = before + arg + after;
|
||||
widget.pos += arg.length;
|
||||
$widget.insert_pos = $widget.pos;
|
||||
$widget.insert_text = arg;
|
||||
const before = $widget.s.slice(0, $widget.pos);
|
||||
const after = $widget.s.slice($widget.pos);
|
||||
$widget.s = before + arg + after;
|
||||
$widget.pos += arg.length;
|
||||
return this;
|
||||
}
|
||||
|
||||
return widget.pos;
|
||||
return $widget.pos;
|
||||
};
|
||||
|
||||
widget.val = function (new_val) {
|
||||
$widget.val = function (new_val) {
|
||||
if (new_val) {
|
||||
widget.s = new_val;
|
||||
$widget.s = new_val;
|
||||
return this;
|
||||
}
|
||||
return widget.s;
|
||||
return $widget.s;
|
||||
};
|
||||
|
||||
widget.trigger = function (type) {
|
||||
$widget.trigger = function (type) {
|
||||
if (type === "focus") {
|
||||
widget.focused = true;
|
||||
$widget.focused = true;
|
||||
} else if (type === "blur") {
|
||||
widget.focused = false;
|
||||
$widget.focused = false;
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
return widget;
|
||||
return $widget;
|
||||
}
|
||||
|
||||
run_test("autosize_textarea", ({override}) => {
|
||||
@@ -121,59 +121,59 @@ run_test("insert_syntax_and_focus", () => {
|
||||
});
|
||||
|
||||
run_test("smart_insert", () => {
|
||||
let textbox = make_textbox("abc");
|
||||
textbox.caret(4);
|
||||
let $textbox = make_textbox("abc");
|
||||
$textbox.caret(4);
|
||||
|
||||
compose_ui.smart_insert(textbox, ":smile:");
|
||||
assert.equal(textbox.insert_pos, 4);
|
||||
assert.equal(textbox.insert_text, " :smile: ");
|
||||
assert.equal(textbox.val(), "abc :smile: ");
|
||||
assert.ok(textbox.focused);
|
||||
compose_ui.smart_insert($textbox, ":smile:");
|
||||
assert.equal($textbox.insert_pos, 4);
|
||||
assert.equal($textbox.insert_text, " :smile: ");
|
||||
assert.equal($textbox.val(), "abc :smile: ");
|
||||
assert.ok($textbox.focused);
|
||||
|
||||
textbox.trigger("blur");
|
||||
compose_ui.smart_insert(textbox, ":airplane:");
|
||||
assert.equal(textbox.insert_text, ":airplane: ");
|
||||
assert.equal(textbox.val(), "abc :smile: :airplane: ");
|
||||
assert.ok(textbox.focused);
|
||||
$textbox.trigger("blur");
|
||||
compose_ui.smart_insert($textbox, ":airplane:");
|
||||
assert.equal($textbox.insert_text, ":airplane: ");
|
||||
assert.equal($textbox.val(), "abc :smile: :airplane: ");
|
||||
assert.ok($textbox.focused);
|
||||
|
||||
textbox.caret(0);
|
||||
textbox.trigger("blur");
|
||||
compose_ui.smart_insert(textbox, ":octopus:");
|
||||
assert.equal(textbox.insert_text, ":octopus: ");
|
||||
assert.equal(textbox.val(), ":octopus: abc :smile: :airplane: ");
|
||||
assert.ok(textbox.focused);
|
||||
$textbox.caret(0);
|
||||
$textbox.trigger("blur");
|
||||
compose_ui.smart_insert($textbox, ":octopus:");
|
||||
assert.equal($textbox.insert_text, ":octopus: ");
|
||||
assert.equal($textbox.val(), ":octopus: abc :smile: :airplane: ");
|
||||
assert.ok($textbox.focused);
|
||||
|
||||
textbox.caret(textbox.val().length);
|
||||
textbox.trigger("blur");
|
||||
compose_ui.smart_insert(textbox, ":heart:");
|
||||
assert.equal(textbox.insert_text, ":heart: ");
|
||||
assert.equal(textbox.val(), ":octopus: abc :smile: :airplane: :heart: ");
|
||||
assert.ok(textbox.focused);
|
||||
$textbox.caret($textbox.val().length);
|
||||
$textbox.trigger("blur");
|
||||
compose_ui.smart_insert($textbox, ":heart:");
|
||||
assert.equal($textbox.insert_text, ":heart: ");
|
||||
assert.equal($textbox.val(), ":octopus: abc :smile: :airplane: :heart: ");
|
||||
assert.ok($textbox.focused);
|
||||
|
||||
// Test handling of spaces for ```quote
|
||||
textbox = make_textbox("");
|
||||
textbox.caret(0);
|
||||
textbox.trigger("blur");
|
||||
compose_ui.smart_insert(textbox, "```quote\nquoted message\n```\n");
|
||||
assert.equal(textbox.insert_text, "```quote\nquoted message\n```\n");
|
||||
assert.equal(textbox.val(), "```quote\nquoted message\n```\n");
|
||||
assert.ok(textbox.focused);
|
||||
$textbox = make_textbox("");
|
||||
$textbox.caret(0);
|
||||
$textbox.trigger("blur");
|
||||
compose_ui.smart_insert($textbox, "```quote\nquoted message\n```\n");
|
||||
assert.equal($textbox.insert_text, "```quote\nquoted message\n```\n");
|
||||
assert.equal($textbox.val(), "```quote\nquoted message\n```\n");
|
||||
assert.ok($textbox.focused);
|
||||
|
||||
textbox = make_textbox("");
|
||||
textbox.caret(0);
|
||||
textbox.trigger("blur");
|
||||
compose_ui.smart_insert(textbox, "translated: [Quoting…]\n");
|
||||
assert.equal(textbox.insert_text, "translated: [Quoting…]\n");
|
||||
assert.equal(textbox.val(), "translated: [Quoting…]\n");
|
||||
assert.ok(textbox.focused);
|
||||
$textbox = make_textbox("");
|
||||
$textbox.caret(0);
|
||||
$textbox.trigger("blur");
|
||||
compose_ui.smart_insert($textbox, "translated: [Quoting…]\n");
|
||||
assert.equal($textbox.insert_text, "translated: [Quoting…]\n");
|
||||
assert.equal($textbox.val(), "translated: [Quoting…]\n");
|
||||
assert.ok($textbox.focused);
|
||||
|
||||
textbox = make_textbox("abc");
|
||||
textbox.caret(3);
|
||||
textbox.trigger("blur");
|
||||
compose_ui.smart_insert(textbox, " test with space");
|
||||
assert.equal(textbox.insert_text, " test with space ");
|
||||
assert.equal(textbox.val(), "abc test with space ");
|
||||
assert.ok(textbox.focused);
|
||||
$textbox = make_textbox("abc");
|
||||
$textbox.caret(3);
|
||||
$textbox.trigger("blur");
|
||||
compose_ui.smart_insert($textbox, " test with space");
|
||||
assert.equal($textbox.insert_text, " test with space ");
|
||||
assert.equal($textbox.val(), "abc test with space ");
|
||||
assert.ok($textbox.focused);
|
||||
|
||||
// Note that we don't have any special logic for strings that are
|
||||
// already surrounded by spaces, since we are usually inserting things
|
||||
@@ -481,14 +481,14 @@ run_test("format_text", () => {
|
||||
wrap_syntax = "";
|
||||
}
|
||||
|
||||
const textarea = $("#compose-textarea");
|
||||
textarea.get = () => ({
|
||||
const $textarea = $("#compose-textarea");
|
||||
$textarea.get = () => ({
|
||||
setSelectionRange: () => {},
|
||||
});
|
||||
|
||||
function init_textarea(val, range) {
|
||||
textarea.val = () => val;
|
||||
textarea.range = () => range;
|
||||
$textarea.val = () => val;
|
||||
$textarea.range = () => range;
|
||||
}
|
||||
|
||||
const italic_syntax = "*";
|
||||
@@ -502,7 +502,7 @@ run_test("format_text", () => {
|
||||
text: "abc",
|
||||
length: 3,
|
||||
});
|
||||
compose_ui.format_text(textarea, "bold");
|
||||
compose_ui.format_text($textarea, "bold");
|
||||
assert.equal(set_text, "");
|
||||
assert.equal(wrap_selection_called, true);
|
||||
assert.equal(wrap_syntax, bold_syntax);
|
||||
@@ -515,7 +515,7 @@ run_test("format_text", () => {
|
||||
text: "abc",
|
||||
length: 7,
|
||||
});
|
||||
compose_ui.format_text(textarea, "bold");
|
||||
compose_ui.format_text($textarea, "bold");
|
||||
assert.equal(set_text, "abc");
|
||||
assert.equal(wrap_selection_called, false);
|
||||
|
||||
@@ -527,7 +527,7 @@ run_test("format_text", () => {
|
||||
text: "**abc**",
|
||||
length: 7,
|
||||
});
|
||||
compose_ui.format_text(textarea, "bold");
|
||||
compose_ui.format_text($textarea, "bold");
|
||||
assert.equal(set_text, "abc");
|
||||
assert.equal(wrap_selection_called, false);
|
||||
|
||||
@@ -539,7 +539,7 @@ run_test("format_text", () => {
|
||||
text: "abc",
|
||||
length: 3,
|
||||
});
|
||||
compose_ui.format_text(textarea, "italic");
|
||||
compose_ui.format_text($textarea, "italic");
|
||||
assert.equal(set_text, "");
|
||||
assert.equal(wrap_selection_called, true);
|
||||
assert.equal(wrap_syntax, italic_syntax);
|
||||
@@ -552,7 +552,7 @@ run_test("format_text", () => {
|
||||
text: "abc",
|
||||
length: 3,
|
||||
});
|
||||
compose_ui.format_text(textarea, "italic");
|
||||
compose_ui.format_text($textarea, "italic");
|
||||
assert.equal(set_text, "abc");
|
||||
assert.equal(wrap_selection_called, false);
|
||||
|
||||
@@ -564,7 +564,7 @@ run_test("format_text", () => {
|
||||
text: "*abc*",
|
||||
length: 5,
|
||||
});
|
||||
compose_ui.format_text(textarea, "italic");
|
||||
compose_ui.format_text($textarea, "italic");
|
||||
assert.equal(set_text, "abc");
|
||||
assert.equal(wrap_selection_called, false);
|
||||
|
||||
@@ -576,7 +576,7 @@ run_test("format_text", () => {
|
||||
text: "abc",
|
||||
length: 3,
|
||||
});
|
||||
compose_ui.format_text(textarea, "bold");
|
||||
compose_ui.format_text($textarea, "bold");
|
||||
assert.equal(set_text, "*abc*");
|
||||
assert.equal(wrap_selection_called, false);
|
||||
|
||||
@@ -588,7 +588,7 @@ run_test("format_text", () => {
|
||||
text: "***abc***",
|
||||
length: 9,
|
||||
});
|
||||
compose_ui.format_text(textarea, "bold");
|
||||
compose_ui.format_text($textarea, "bold");
|
||||
assert.equal(set_text, "*abc*");
|
||||
assert.equal(wrap_selection_called, false);
|
||||
|
||||
@@ -600,7 +600,7 @@ run_test("format_text", () => {
|
||||
text: "abc",
|
||||
length: 3,
|
||||
});
|
||||
compose_ui.format_text(textarea, "italic");
|
||||
compose_ui.format_text($textarea, "italic");
|
||||
assert.equal(set_text, "**abc**");
|
||||
assert.equal(wrap_selection_called, false);
|
||||
|
||||
@@ -612,14 +612,14 @@ run_test("format_text", () => {
|
||||
text: "***abc***",
|
||||
length: 9,
|
||||
});
|
||||
compose_ui.format_text(textarea, "italic");
|
||||
compose_ui.format_text($textarea, "italic");
|
||||
assert.equal(set_text, "**abc**");
|
||||
assert.equal(wrap_selection_called, false);
|
||||
});
|
||||
|
||||
run_test("markdown_shortcuts", ({override_rewire}) => {
|
||||
let format_text_type;
|
||||
override_rewire(compose_ui, "format_text", (textarea, type) => {
|
||||
override_rewire(compose_ui, "format_text", ($textarea, type) => {
|
||||
format_text_type = type;
|
||||
});
|
||||
|
||||
@@ -711,21 +711,21 @@ run_test("markdown_shortcuts", ({override_rewire}) => {
|
||||
});
|
||||
|
||||
run_test("right-to-left", () => {
|
||||
const textarea = $("#compose-textarea");
|
||||
const $textarea = $("#compose-textarea");
|
||||
|
||||
const event = {
|
||||
key: "A",
|
||||
};
|
||||
|
||||
assert.equal(textarea.hasClass("rtl"), false);
|
||||
assert.equal($textarea.hasClass("rtl"), false);
|
||||
|
||||
textarea.val("```quote\nمرحبا");
|
||||
$textarea.val("```quote\nمرحبا");
|
||||
compose_ui.handle_keyup(event, $("#compose-textarea"));
|
||||
|
||||
assert.equal(textarea.hasClass("rtl"), true);
|
||||
assert.equal($textarea.hasClass("rtl"), true);
|
||||
|
||||
textarea.val("```quote foo");
|
||||
compose_ui.handle_keyup(event, textarea);
|
||||
$textarea.val("```quote foo");
|
||||
compose_ui.handle_keyup(event, $textarea);
|
||||
|
||||
assert.equal(textarea.hasClass("rtl"), false);
|
||||
assert.equal($textarea.hasClass("rtl"), false);
|
||||
});
|
||||
|
||||
@@ -131,10 +131,10 @@ test_ui("validate", ({override, mock_template}) => {
|
||||
$("#compose-send-button").trigger("focus");
|
||||
$("#compose-send-button .loader").hide();
|
||||
|
||||
const pm_pill_container = $.create("fake-pm-pill-container");
|
||||
const $pm_pill_container = $.create("fake-pm-pill-container");
|
||||
$("#private_message_recipient")[0] = {};
|
||||
$("#private_message_recipient").set_parent(pm_pill_container);
|
||||
pm_pill_container.set_find_results(".input", $("#private_message_recipient"));
|
||||
$("#private_message_recipient").set_parent($pm_pill_container);
|
||||
$pm_pill_container.set_find_results(".input", $("#private_message_recipient"));
|
||||
$("#private_message_recipient").before = () => {};
|
||||
|
||||
compose_pm_pill.initialize();
|
||||
@@ -474,38 +474,38 @@ test_ui("test_validate_stream_message_post_policy_full_members_only", () => {
|
||||
test_ui("test_check_overflow_text", () => {
|
||||
page_params.max_message_length = 10000;
|
||||
|
||||
const textarea = $("#compose-textarea");
|
||||
const indicator = $("#compose_limit_indicator");
|
||||
const send_button = $("#compose-send-button");
|
||||
const $textarea = $("#compose-textarea");
|
||||
const $indicator = $("#compose_limit_indicator");
|
||||
const $send_button = $("#compose-send-button");
|
||||
|
||||
// Indicator should show red colored text
|
||||
textarea.val("a".repeat(10000 + 1));
|
||||
$textarea.val("a".repeat(10000 + 1));
|
||||
compose_validate.check_overflow_text();
|
||||
assert.ok(indicator.hasClass("over_limit"));
|
||||
assert.equal(indicator.text(), "10001/10000");
|
||||
assert.ok(textarea.hasClass("over_limit"));
|
||||
assert.ok($indicator.hasClass("over_limit"));
|
||||
assert.equal($indicator.text(), "10001/10000");
|
||||
assert.ok($textarea.hasClass("over_limit"));
|
||||
assert.equal(
|
||||
$("#compose-error-msg").html(),
|
||||
"translated HTML: Message length shouldn't be greater than 10000 characters.",
|
||||
);
|
||||
assert.ok(send_button.prop("disabled"));
|
||||
assert.ok($send_button.prop("disabled"));
|
||||
|
||||
$("#compose-send-status").stop = () => ({fadeOut: () => {}});
|
||||
|
||||
// Indicator should show orange colored text
|
||||
textarea.val("a".repeat(9000 + 1));
|
||||
$textarea.val("a".repeat(9000 + 1));
|
||||
compose_validate.check_overflow_text();
|
||||
assert.ok(!indicator.hasClass("over_limit"));
|
||||
assert.equal(indicator.text(), "9001/10000");
|
||||
assert.ok(!textarea.hasClass("over_limit"));
|
||||
assert.ok(!send_button.prop("disabled"));
|
||||
assert.ok(!$indicator.hasClass("over_limit"));
|
||||
assert.equal($indicator.text(), "9001/10000");
|
||||
assert.ok(!$textarea.hasClass("over_limit"));
|
||||
assert.ok(!$send_button.prop("disabled"));
|
||||
|
||||
// Indicator must be empty
|
||||
textarea.val("a".repeat(9000));
|
||||
$textarea.val("a".repeat(9000));
|
||||
compose_validate.check_overflow_text();
|
||||
assert.ok(!indicator.hasClass("over_limit"));
|
||||
assert.equal(indicator.text(), "");
|
||||
assert.ok(!textarea.hasClass("over_limit"));
|
||||
assert.ok(!$indicator.hasClass("over_limit"));
|
||||
assert.equal($indicator.text(), "");
|
||||
assert.ok(!$textarea.hasClass("over_limit"));
|
||||
});
|
||||
|
||||
test_ui("test_message_overflow", () => {
|
||||
@@ -736,10 +736,10 @@ test_ui("warn_if_mentioning_unsubscribed_user", ({override, override_rewire, moc
|
||||
}
|
||||
|
||||
// Simulate that the row was added to the DOM.
|
||||
const warning_row = $("<warning row>");
|
||||
const $warning_row = $("<warning-row-stub>");
|
||||
|
||||
let looked_for_existing;
|
||||
warning_row.data = (field) => {
|
||||
$warning_row.data = (field) => {
|
||||
if (field === "user-id") {
|
||||
looked_for_existing = true;
|
||||
return "34";
|
||||
@@ -750,9 +750,9 @@ test_ui("warn_if_mentioning_unsubscribed_user", ({override, override_rewire, moc
|
||||
throw new Error(`Unknown field ${field}`);
|
||||
};
|
||||
|
||||
const previous_users = $("#compose_invite_users .compose_invite_user");
|
||||
previous_users.length = 1;
|
||||
previous_users[0] = warning_row;
|
||||
const $previous_users = $("#compose_invite_users .compose_invite_user");
|
||||
$previous_users.length = 1;
|
||||
$previous_users[0] = $warning_row;
|
||||
$("#compose_invite_users").hide();
|
||||
|
||||
// Now try to mention the same person again. The template should
|
||||
@@ -788,12 +788,12 @@ test_ui("test warn_if_topic_resolved", ({override, mock_template}) => {
|
||||
stream_data.add_sub(sub);
|
||||
|
||||
// The error message area where it is shown
|
||||
const error_area = $("#compose_resolved_topic");
|
||||
const $error_area = $("#compose_resolved_topic");
|
||||
compose_validate.clear_topic_resolved_warning();
|
||||
// Hack to make this empty for zjquery; this is conceptually done
|
||||
// in the previous line.
|
||||
error_area.html("");
|
||||
assert.ok(!error_area.visible());
|
||||
$error_area.html("");
|
||||
assert.ok(!$error_area.visible());
|
||||
|
||||
compose_state.set_message_type("stream");
|
||||
compose_state.stream_name("Do not exist");
|
||||
@@ -802,25 +802,25 @@ test_ui("test warn_if_topic_resolved", ({override, mock_template}) => {
|
||||
|
||||
// Do not show a warning if stream name does not exist
|
||||
compose_validate.warn_if_topic_resolved(true);
|
||||
assert.ok(!error_area.visible());
|
||||
assert.ok(!$error_area.visible());
|
||||
|
||||
compose_state.stream_name("random");
|
||||
|
||||
// Show the warning now as stream also exists
|
||||
compose_validate.warn_if_topic_resolved(true);
|
||||
assert.ok(error_area.visible());
|
||||
assert.ok($error_area.visible());
|
||||
|
||||
// Call it again with false; this should be a noop.
|
||||
compose_validate.warn_if_topic_resolved(false);
|
||||
assert.ok(error_area.visible());
|
||||
assert.ok($error_area.visible());
|
||||
|
||||
compose_state.topic("hello");
|
||||
|
||||
// The warning will be cleared now
|
||||
compose_validate.warn_if_topic_resolved(true);
|
||||
assert.ok(!error_area.visible());
|
||||
assert.ok(!$error_area.visible());
|
||||
|
||||
// Calling with false won't do anything.
|
||||
compose_validate.warn_if_topic_resolved(false);
|
||||
assert.ok(!error_area.visible());
|
||||
assert.ok(!$error_area.visible());
|
||||
});
|
||||
|
||||
@@ -27,14 +27,15 @@ set_global("ResizeObserver", function () {
|
||||
|
||||
const server_events_dispatch = zrequire("server_events_dispatch");
|
||||
const compose_ui = zrequire("compose_ui");
|
||||
const compose_closed = zrequire("compose_closed_ui");
|
||||
const compose = zrequire("compose");
|
||||
function stub_out_video_calls() {
|
||||
const elem = $("#below-compose-content .video_link");
|
||||
elem.toggle = (show) => {
|
||||
const $elem = $("#below-compose-content .video_link");
|
||||
$elem.toggle = (show) => {
|
||||
if (show) {
|
||||
elem.show();
|
||||
$elem.show();
|
||||
} else {
|
||||
elem.hide();
|
||||
$elem.hide();
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -78,14 +79,14 @@ test("videos", ({override, override_rewire}) => {
|
||||
(function test_no_provider_video_link_compose_clicked() {
|
||||
let called = false;
|
||||
|
||||
const textarea = $.create("target-stub");
|
||||
textarea.set_parents_result(".message_edit_form", []);
|
||||
const $textarea = $.create("target-stub");
|
||||
$textarea.set_parents_result(".message_edit_form", []);
|
||||
|
||||
const ev = {
|
||||
preventDefault: () => {},
|
||||
stopPropagation: () => {},
|
||||
target: {
|
||||
to_$: () => textarea,
|
||||
to_$: () => $textarea,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -104,14 +105,14 @@ test("videos", ({override, override_rewire}) => {
|
||||
let syntax_to_insert;
|
||||
let called = false;
|
||||
|
||||
const textarea = $.create("jitsi-target-stub");
|
||||
textarea.set_parents_result(".message_edit_form", []);
|
||||
const $textarea = $.create("jitsi-target-stub");
|
||||
$textarea.set_parents_result(".message_edit_form", []);
|
||||
|
||||
const ev = {
|
||||
preventDefault: () => {},
|
||||
stopPropagation: () => {},
|
||||
target: {
|
||||
to_$: () => textarea,
|
||||
to_$: () => $textarea,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -142,14 +143,14 @@ test("videos", ({override, override_rewire}) => {
|
||||
let syntax_to_insert;
|
||||
let called = false;
|
||||
|
||||
const textarea = $.create("zoom-target-stub");
|
||||
textarea.set_parents_result(".message_edit_form", []);
|
||||
const $textarea = $.create("zoom-target-stub");
|
||||
$textarea.set_parents_result(".message_edit_form", []);
|
||||
|
||||
const ev = {
|
||||
preventDefault: () => {},
|
||||
stopPropagation: () => {},
|
||||
target: {
|
||||
to_$: () => textarea,
|
||||
to_$: () => $textarea,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -188,14 +189,14 @@ test("videos", ({override, override_rewire}) => {
|
||||
let syntax_to_insert;
|
||||
let called = false;
|
||||
|
||||
const textarea = $.create("bbb-target-stub");
|
||||
textarea.set_parents_result(".message_edit_form", []);
|
||||
const $textarea = $.create("bbb-target-stub");
|
||||
$textarea.set_parents_result(".message_edit_form", []);
|
||||
|
||||
const ev = {
|
||||
preventDefault: () => {},
|
||||
stopPropagation: () => {},
|
||||
target: {
|
||||
to_$: () => textarea,
|
||||
to_$: () => $textarea,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -210,8 +211,11 @@ test("videos", ({override, override_rewire}) => {
|
||||
page_params.realm_video_chat_provider =
|
||||
realm_available_video_chat_providers.big_blue_button.id;
|
||||
|
||||
compose_closed.get_recipient_label = () => "a";
|
||||
|
||||
channel.get = (options) => {
|
||||
assert.equal(options.url, "/json/calls/bigbluebutton/create");
|
||||
assert.equal(options.data.meeting_name, "a meeting");
|
||||
options.success({
|
||||
url: "/calls/bigbluebutton/join?meeting_id=%22zulip-1%22&password=%22AAAAAAAAAA%22&checksum=%2232702220bff2a22a44aee72e96cfdb4c4091752e%22",
|
||||
});
|
||||
|
||||
@@ -498,10 +498,20 @@ run_test("realm_bot remove", ({override}) => {
|
||||
admin_stub.get_args("update_user_id", "update_bot_data");
|
||||
});
|
||||
|
||||
run_test("realm_bot delete", () => {
|
||||
run_test("realm_bot delete", ({override}) => {
|
||||
const event = event_fixtures.realm_bot__delete;
|
||||
// We don't handle live updates for delete events, this is a noop.
|
||||
const bot_stub = make_stub();
|
||||
const admin_stub = make_stub();
|
||||
override(bot_data, "del", bot_stub.f);
|
||||
override(settings_bots, "render_bots", () => {});
|
||||
override(settings_users, "redraw_bots_list", admin_stub.f);
|
||||
|
||||
dispatch(event);
|
||||
assert.equal(bot_stub.num_calls, 1);
|
||||
const args = bot_stub.get_args("user_id");
|
||||
assert_same(args.user_id, event.bot.user_id);
|
||||
|
||||
assert.equal(admin_stub.num_calls, 1);
|
||||
});
|
||||
|
||||
run_test("realm_bot update", ({override}) => {
|
||||
|
||||
@@ -120,8 +120,8 @@ test("draft_model add", ({override}) => {
|
||||
const ls = localstorage();
|
||||
assert.equal(ls.get("draft"), undefined);
|
||||
|
||||
const unread_count = $('<span class="unread_count"></span>');
|
||||
$(".top_left_drafts").set_find_results(".unread_count", unread_count);
|
||||
const $unread_count = $("<unread-count-stub>");
|
||||
$(".top_left_drafts").set_find_results(".unread_count", $unread_count);
|
||||
|
||||
override(Date, "now", () => 1);
|
||||
const expected = {...draft_1};
|
||||
@@ -136,8 +136,8 @@ test("draft_model edit", () => {
|
||||
assert.equal(ls.get("draft"), undefined);
|
||||
let id;
|
||||
|
||||
const unread_count = $('<span class="unread_count"></span>');
|
||||
$(".top_left_drafts").set_find_results(".unread_count", unread_count);
|
||||
const $unread_count = $("<unread-count-stub>");
|
||||
$(".top_left_drafts").set_find_results(".unread_count", $unread_count);
|
||||
|
||||
with_overrides(({override}) => {
|
||||
override(Date, "now", () => 1);
|
||||
@@ -161,8 +161,8 @@ test("draft_model delete", ({override}) => {
|
||||
const ls = localstorage();
|
||||
assert.equal(ls.get("draft"), undefined);
|
||||
|
||||
const unread_count = $('<span class="unread_count"></span>');
|
||||
$(".top_left_drafts").set_find_results(".unread_count", unread_count);
|
||||
const $unread_count = $("<unread-count-stub>");
|
||||
$(".top_left_drafts").set_find_results(".unread_count", $unread_count);
|
||||
|
||||
override(Date, "now", () => 1);
|
||||
const expected = {...draft_1};
|
||||
@@ -212,8 +212,8 @@ test("initialize", ({override_rewire}) => {
|
||||
assert.ok(called);
|
||||
};
|
||||
|
||||
const unread_count = $('<span class="unread_count"></span>');
|
||||
$(".top_left_drafts").set_find_results(".unread_count", unread_count);
|
||||
const $unread_count = $("<unread-count-stub>");
|
||||
$(".top_left_drafts").set_find_results(".unread_count", $unread_count);
|
||||
|
||||
drafts.initialize();
|
||||
});
|
||||
@@ -239,8 +239,8 @@ test("remove_old_drafts", () => {
|
||||
ls.set("drafts", data);
|
||||
assert.deepEqual(draft_model.get(), data);
|
||||
|
||||
const unread_count = $('<span class="unread_count"></span>');
|
||||
$(".top_left_drafts").set_find_results(".unread_count", unread_count);
|
||||
const $unread_count = $("<unread-count-stub>");
|
||||
$(".top_left_drafts").set_find_results(".unread_count", $unread_count);
|
||||
|
||||
drafts.remove_old_drafts();
|
||||
assert.deepEqual(draft_model.get(), {id3: draft_3});
|
||||
@@ -256,9 +256,9 @@ test("update_draft", ({override}) => {
|
||||
override(compose_state, "get_message_type", () => "private");
|
||||
override(compose_state, "private_message_recipient", () => "aaron@zulip.com");
|
||||
|
||||
const container = $(".top_left_drafts");
|
||||
const child = $(".unread_count");
|
||||
container.set_find_results(".unread_count", child);
|
||||
const $container = $(".top_left_drafts");
|
||||
const $child = $(".unread_count");
|
||||
$container.set_find_results(".unread_count", $child);
|
||||
|
||||
tippy_args = {
|
||||
content: "translated: Saved as draft",
|
||||
@@ -313,8 +313,8 @@ test("delete_all_drafts", () => {
|
||||
ls.set("drafts", data);
|
||||
assert.deepEqual(draft_model.get(), data);
|
||||
|
||||
const unread_count = $('<span class="unread_count"></span>');
|
||||
$(".top_left_drafts").set_find_results(".unread_count", unread_count);
|
||||
const $unread_count = $("<unread-count-stub>");
|
||||
$(".top_left_drafts").set_find_results(".unread_count", $unread_count);
|
||||
|
||||
drafts.delete_all_drafts();
|
||||
assert.deepEqual(draft_model.get(), {});
|
||||
@@ -451,8 +451,8 @@ test("format_drafts", ({override_rewire, mock_template}) => {
|
||||
|
||||
expected[0].stream_name = "stream-rename";
|
||||
|
||||
const unread_count = $('<span class="unread_count"></span>');
|
||||
$(".top_left_drafts").set_find_results(".unread_count", unread_count);
|
||||
const $unread_count = $("<unread-count-stub>");
|
||||
$(".top_left_drafts").set_find_results(".unread_count", $unread_count);
|
||||
|
||||
drafts.launch();
|
||||
timerender.__Rewire__("render_now", stub_render_now);
|
||||
|
||||
@@ -25,12 +25,12 @@ const {DropdownListWidget, MultiSelectDropdownListWidget} = zrequire("dropdown_l
|
||||
|
||||
// For DropdownListWidget
|
||||
const setup_dropdown_zjquery_data = (name) => {
|
||||
const input_group = $(".input_group");
|
||||
const reset_button = $(".dropdown_list_reset_button");
|
||||
input_group.set_find_results(".dropdown_list_reset_button", reset_button);
|
||||
$(`#${CSS.escape(name)}_widget #${CSS.escape(name)}_name`).closest = () => input_group;
|
||||
const $input_group = $(".input_group");
|
||||
const $reset_button = $(".dropdown_list_reset_button");
|
||||
$input_group.set_find_results(".dropdown_list_reset_button", $reset_button);
|
||||
$(`#${CSS.escape(name)}_widget #${CSS.escape(name)}_name`).closest = () => $input_group;
|
||||
const $widget = $(`#${CSS.escape(name)}_widget #${CSS.escape(name)}_name`);
|
||||
return {reset_button, $widget};
|
||||
return {$reset_button, $widget};
|
||||
};
|
||||
|
||||
run_test("basic_functions", () => {
|
||||
@@ -46,31 +46,31 @@ run_test("basic_functions", () => {
|
||||
render_text: (text) => `rendered: ${text}`,
|
||||
};
|
||||
|
||||
const {reset_button, $widget} = setup_dropdown_zjquery_data(opts.widget_name);
|
||||
const {$reset_button, $widget} = setup_dropdown_zjquery_data(opts.widget_name);
|
||||
|
||||
const widget = new DropdownListWidget(opts);
|
||||
|
||||
assert.equal(widget.value(), "one");
|
||||
assert.equal(updated_value, undefined); // We haven't 'updated' the widget yet.
|
||||
assert.ok(reset_button.visible());
|
||||
assert.ok($reset_button.visible());
|
||||
|
||||
widget.update("two");
|
||||
assert.equal($widget.text(), "rendered: two");
|
||||
assert.equal(widget.value(), "two");
|
||||
assert.equal(updated_value, "two");
|
||||
assert.ok(reset_button.visible());
|
||||
assert.ok($reset_button.visible());
|
||||
|
||||
widget.update(null);
|
||||
assert.equal($widget.text(), "translated: not set");
|
||||
assert.equal(widget.value(), "");
|
||||
assert.equal(updated_value, null);
|
||||
assert.ok(!reset_button.visible());
|
||||
assert.ok(!$reset_button.visible());
|
||||
|
||||
widget.update("four");
|
||||
assert.equal($widget.text(), "translated: not set");
|
||||
assert.equal(widget.value(), "four");
|
||||
assert.equal(updated_value, "four");
|
||||
assert.ok(!reset_button.visible());
|
||||
assert.ok(!$reset_button.visible());
|
||||
});
|
||||
|
||||
run_test("no_default_value", () => {
|
||||
@@ -110,7 +110,7 @@ run_test("basic MDLW functions", () => {
|
||||
default_text: $t({defaultMessage: "not set"}),
|
||||
};
|
||||
|
||||
const {reset_button, $widget} = setup_multiselect_dropdown_zjquery_data(opts.widget_name);
|
||||
const {$reset_button, $widget} = setup_multiselect_dropdown_zjquery_data(opts.widget_name);
|
||||
const widget = new MultiSelectDropdownListWidget(opts);
|
||||
|
||||
function set_dropdown_variables(widget, value) {
|
||||
@@ -121,7 +121,7 @@ run_test("basic MDLW functions", () => {
|
||||
assert.deepEqual(widget.value(), ["one"]);
|
||||
assert.equal(updated_value, undefined);
|
||||
assert.equal($widget.text(), "one");
|
||||
assert.ok(reset_button.visible());
|
||||
assert.ok($reset_button.visible());
|
||||
|
||||
set_dropdown_variables(widget, ["one", "two"]);
|
||||
widget.update(widget.data_selected);
|
||||
@@ -129,7 +129,7 @@ run_test("basic MDLW functions", () => {
|
||||
assert.equal($widget.text(), "one,two");
|
||||
assert.deepEqual(widget.value(), ["one", "two"]);
|
||||
assert.deepEqual(updated_value, ["one", "two"]);
|
||||
assert.ok(reset_button.visible());
|
||||
assert.ok($reset_button.visible());
|
||||
|
||||
set_dropdown_variables(widget, ["one", "two", "three"]);
|
||||
widget.update(widget.data_selected);
|
||||
@@ -137,7 +137,7 @@ run_test("basic MDLW functions", () => {
|
||||
assert.equal($widget.text(), "translated: 3 selected");
|
||||
assert.deepEqual(widget.value(), ["one", "two", "three"]);
|
||||
assert.deepEqual(updated_value, ["one", "two", "three"]);
|
||||
assert.ok(reset_button.visible());
|
||||
assert.ok($reset_button.visible());
|
||||
|
||||
set_dropdown_variables(widget, null);
|
||||
widget.update(widget.data_selected);
|
||||
@@ -145,7 +145,7 @@ run_test("basic MDLW functions", () => {
|
||||
assert.equal($widget.text(), "translated: not set");
|
||||
assert.equal(widget.value(), null);
|
||||
assert.equal(updated_value, null);
|
||||
assert.ok(!reset_button.visible());
|
||||
assert.ok(!$reset_button.visible());
|
||||
|
||||
set_dropdown_variables(widget, ["one"]);
|
||||
widget.update(widget.data_selected);
|
||||
@@ -153,7 +153,7 @@ run_test("basic MDLW functions", () => {
|
||||
assert.equal($widget.text(), "one");
|
||||
assert.deepEqual(widget.value(), ["one"]);
|
||||
assert.deepEqual(updated_value, ["one"]);
|
||||
assert.ok(reset_button.visible());
|
||||
assert.ok($reset_button.visible());
|
||||
});
|
||||
|
||||
run_test("MDLW no_default_value", () => {
|
||||
|
||||
@@ -29,6 +29,8 @@ const message_store = mock_esm("../../static/js/message_store", {
|
||||
get: () => ({failed_request: true}),
|
||||
|
||||
update_booleans: () => {},
|
||||
|
||||
set_message_booleans: () => {},
|
||||
});
|
||||
|
||||
mock_esm("../../static/js/message_list");
|
||||
|
||||
@@ -64,14 +64,13 @@ run_test("message_store", () => {
|
||||
const in_message = {...messages.isaac_to_denmark_stream};
|
||||
|
||||
assert.equal(in_message.alerted, undefined);
|
||||
message_store.set_message_booleans(in_message);
|
||||
assert.equal(in_message.alerted, true);
|
||||
|
||||
// Let's add a message into our message_store via
|
||||
// message_helper.process_new_message.
|
||||
assert.equal(message_store.get(in_message.id), undefined);
|
||||
message_helper.process_new_message(in_message);
|
||||
const message = message_store.get(in_message.id);
|
||||
assert.equal(in_message.alerted, true);
|
||||
assert.equal(message, in_message);
|
||||
|
||||
// There are more side effects.
|
||||
|
||||
@@ -67,7 +67,7 @@ people.add_active_user(kitty);
|
||||
*/
|
||||
run_test("typing_events.render_notifications_for_narrow", ({override_rewire, mock_template}) => {
|
||||
// All typists are rendered in `#typing_notifications`.
|
||||
const typing_notifications = $("#typing_notifications");
|
||||
const $typing_notifications = $("#typing_notifications");
|
||||
|
||||
const two_typing_users_ids = [anna.user_id, vronsky.user_id];
|
||||
const two_typing_users = [anna, vronsky];
|
||||
@@ -107,7 +107,7 @@ run_test("typing_events.render_notifications_for_narrow", ({override_rewire, moc
|
||||
typing_events.render_notifications_for_narrow();
|
||||
// Make sure #typing_notifications's html content is set to the rendered template
|
||||
// which we mocked and gave a custom return value.
|
||||
assert.equal(typing_notifications.html(), two_typing_users_rendered_html);
|
||||
assert.equal($typing_notifications.html(), two_typing_users_rendered_html);
|
||||
|
||||
// Now we'll see how setting the second argument to `true`
|
||||
// can be helpful in testing conditionals inside the template.
|
||||
@@ -118,9 +118,9 @@ run_test("typing_events.render_notifications_for_narrow", ({override_rewire, moc
|
||||
// Since we only have two(<MAX_USERS_TO_DISPLAY_NAME) typists, both of them
|
||||
// should be rendered but not 'Several people are typing…'
|
||||
typing_events.render_notifications_for_narrow();
|
||||
assert.ok(typing_notifications.html().includes(`${anna.full_name} is typing…`));
|
||||
assert.ok(typing_notifications.html().includes(`${vronsky.full_name} is typing…`));
|
||||
assert.ok(!typing_notifications.html().includes("Several people are typing…"));
|
||||
assert.ok($typing_notifications.html().includes(`${anna.full_name} is typing…`));
|
||||
assert.ok($typing_notifications.html().includes(`${vronsky.full_name} is typing…`));
|
||||
assert.ok(!$typing_notifications.html().includes("Several people are typing…"));
|
||||
|
||||
// Change to having four typists and verify the rendered html has
|
||||
// 'Several people are typing…' but not the list of users.
|
||||
@@ -128,9 +128,9 @@ run_test("typing_events.render_notifications_for_narrow", ({override_rewire, moc
|
||||
override_rewire(typing_events, "get_users_typing_for_narrow", () => four_typing_users_ids);
|
||||
|
||||
typing_events.render_notifications_for_narrow();
|
||||
assert.ok(typing_notifications.html().includes("Several people are typing…"));
|
||||
assert.ok(!typing_notifications.html().includes(`${anna.full_name} is typing…`));
|
||||
assert.ok(!typing_notifications.html().includes(`${vronsky.full_name} is typing…`));
|
||||
assert.ok(!typing_notifications.html().includes(`${levin.full_name} is typing…`));
|
||||
assert.ok(!typing_notifications.html().includes(`${kitty.full_name} is typing…`));
|
||||
assert.ok($typing_notifications.html().includes("Several people are typing…"));
|
||||
assert.ok(!$typing_notifications.html().includes(`${anna.full_name} is typing…`));
|
||||
assert.ok(!$typing_notifications.html().includes(`${vronsky.full_name} is typing…`));
|
||||
assert.ok(!$typing_notifications.html().includes(`${levin.full_name} is typing…`));
|
||||
assert.ok(!$typing_notifications.html().includes(`${kitty.full_name} is typing…`));
|
||||
});
|
||||
|
||||
@@ -8,8 +8,8 @@ const blueslip = require("../zjsunit/zblueslip");
|
||||
const $ = require("../zjsunit/zjquery");
|
||||
const {user_settings} = require("../zjsunit/zpage_params");
|
||||
|
||||
let window_stub;
|
||||
set_global("to_$", () => window_stub);
|
||||
let $window_stub;
|
||||
set_global("to_$", () => $window_stub);
|
||||
|
||||
mock_esm("../../static/js/search", {
|
||||
update_button_visibility: () => {},
|
||||
@@ -165,7 +165,7 @@ function test_helper({override, override_rewire, change_tab}) {
|
||||
}
|
||||
|
||||
run_test("hash_interactions", ({override, override_rewire}) => {
|
||||
window_stub = $.create("window-stub");
|
||||
$window_stub = $.create("window-stub");
|
||||
user_settings.default_view = "recent_topics";
|
||||
|
||||
override_rewire(recent_topics_util, "is_visible", () => false);
|
||||
@@ -189,7 +189,7 @@ run_test("hash_interactions", ({override, override_rewire}) => {
|
||||
window.location.hash = "#all_messages";
|
||||
|
||||
helper.clear_events();
|
||||
window_stub.trigger("hashchange");
|
||||
$window_stub.trigger("hashchange");
|
||||
helper.assert_events([
|
||||
[overlays, "close_for_hash_change"],
|
||||
[message_viewport, "stop_auto_scrolling"],
|
||||
@@ -199,7 +199,7 @@ run_test("hash_interactions", ({override, override_rewire}) => {
|
||||
]);
|
||||
|
||||
helper.clear_events();
|
||||
window_stub.trigger("hashchange");
|
||||
$window_stub.trigger("hashchange");
|
||||
helper.assert_events([
|
||||
[overlays, "close_for_hash_change"],
|
||||
[message_viewport, "stop_auto_scrolling"],
|
||||
@@ -211,7 +211,7 @@ run_test("hash_interactions", ({override, override_rewire}) => {
|
||||
window.location.hash = "#narrow/stream/Denmark";
|
||||
|
||||
helper.clear_events();
|
||||
window_stub.trigger("hashchange");
|
||||
$window_stub.trigger("hashchange");
|
||||
helper.assert_events([
|
||||
[overlays, "close_for_hash_change"],
|
||||
[message_viewport, "stop_auto_scrolling"],
|
||||
@@ -225,7 +225,7 @@ run_test("hash_interactions", ({override, override_rewire}) => {
|
||||
window.location.hash = "#narrow";
|
||||
|
||||
helper.clear_events();
|
||||
window_stub.trigger("hashchange");
|
||||
$window_stub.trigger("hashchange");
|
||||
helper.assert_events([
|
||||
[overlays, "close_for_hash_change"],
|
||||
[message_viewport, "stop_auto_scrolling"],
|
||||
@@ -240,7 +240,7 @@ run_test("hash_interactions", ({override, override_rewire}) => {
|
||||
window.location.hash = "#narrow/foo.foo";
|
||||
|
||||
helper.clear_events();
|
||||
window_stub.trigger("hashchange");
|
||||
$window_stub.trigger("hashchange");
|
||||
helper.assert_events([
|
||||
[overlays, "close_for_hash_change"],
|
||||
[message_viewport, "stop_auto_scrolling"],
|
||||
@@ -251,7 +251,7 @@ run_test("hash_interactions", ({override, override_rewire}) => {
|
||||
window.location.hash = "#streams/whatever";
|
||||
|
||||
helper.clear_events();
|
||||
window_stub.trigger("hashchange");
|
||||
$window_stub.trigger("hashchange");
|
||||
helper.assert_events([
|
||||
[overlays, "close_for_hash_change"],
|
||||
[stream_settings_ui, "launch"],
|
||||
@@ -261,7 +261,7 @@ run_test("hash_interactions", ({override, override_rewire}) => {
|
||||
window.location.hash = "#reload:send_after_reload=0...";
|
||||
|
||||
helper.clear_events();
|
||||
window_stub.trigger("hashchange");
|
||||
$window_stub.trigger("hashchange");
|
||||
helper.assert_events([]);
|
||||
// If it's reload hash it shouldn't show the default view.
|
||||
assert.equal(recent_topics_ui_shown, false);
|
||||
@@ -269,25 +269,25 @@ run_test("hash_interactions", ({override, override_rewire}) => {
|
||||
window.location.hash = "#keyboard-shortcuts/whatever";
|
||||
|
||||
helper.clear_events();
|
||||
window_stub.trigger("hashchange");
|
||||
$window_stub.trigger("hashchange");
|
||||
helper.assert_events([[overlays, "close_for_hash_change"], "info: keyboard-shortcuts"]);
|
||||
|
||||
window.location.hash = "#message-formatting/whatever";
|
||||
|
||||
helper.clear_events();
|
||||
window_stub.trigger("hashchange");
|
||||
$window_stub.trigger("hashchange");
|
||||
helper.assert_events([[overlays, "close_for_hash_change"], "info: message-formatting"]);
|
||||
|
||||
window.location.hash = "#search-operators/whatever";
|
||||
|
||||
helper.clear_events();
|
||||
window_stub.trigger("hashchange");
|
||||
$window_stub.trigger("hashchange");
|
||||
helper.assert_events([[overlays, "close_for_hash_change"], "info: search-operators"]);
|
||||
|
||||
window.location.hash = "#drafts";
|
||||
|
||||
helper.clear_events();
|
||||
window_stub.trigger("hashchange");
|
||||
$window_stub.trigger("hashchange");
|
||||
helper.assert_events([
|
||||
[overlays, "close_for_hash_change"],
|
||||
[drafts, "launch"],
|
||||
@@ -296,7 +296,7 @@ run_test("hash_interactions", ({override, override_rewire}) => {
|
||||
window.location.hash = "#settings/alert-words";
|
||||
|
||||
helper.clear_events();
|
||||
window_stub.trigger("hashchange");
|
||||
$window_stub.trigger("hashchange");
|
||||
helper.assert_events([
|
||||
[overlays, "close_for_hash_change"],
|
||||
[settings, "launch"],
|
||||
@@ -305,7 +305,7 @@ run_test("hash_interactions", ({override, override_rewire}) => {
|
||||
window.location.hash = "#organization/user-list-admin";
|
||||
|
||||
helper.clear_events();
|
||||
window_stub.trigger("hashchange");
|
||||
$window_stub.trigger("hashchange");
|
||||
helper.assert_events([
|
||||
[overlays, "close_for_hash_change"],
|
||||
[admin, "launch"],
|
||||
|
||||
@@ -69,12 +69,12 @@ run_test("basics", ({override_rewire, mock_template}) => {
|
||||
blueslip.expect("error", "Pill needs container.");
|
||||
input_pill.create(config);
|
||||
|
||||
const pill_input = $.create("pill_input");
|
||||
const container = $.create("container");
|
||||
container.set_find_results(".input", pill_input);
|
||||
const $pill_input = $.create("pill_input");
|
||||
const $container = $.create("container");
|
||||
$container.set_find_results(".input", $pill_input);
|
||||
|
||||
blueslip.expect("error", "Pill needs create_item_from_text");
|
||||
config.container = container;
|
||||
config.$container = $container;
|
||||
input_pill.create(config);
|
||||
|
||||
blueslip.expect("error", "Pill needs get_text_from_item");
|
||||
@@ -101,9 +101,9 @@ run_test("basics", ({override_rewire, mock_template}) => {
|
||||
let inserted_before;
|
||||
const expected_html = pill_html("JavaScript", "some_id1", example_img_link, status_emoji_info);
|
||||
|
||||
pill_input.before = (elem) => {
|
||||
$pill_input.before = ($elem) => {
|
||||
inserted_before = true;
|
||||
assert.equal(elem.html(), expected_html);
|
||||
assert.equal($elem.html(), expected_html);
|
||||
};
|
||||
|
||||
widget.appendValidatedData(item);
|
||||
@@ -134,27 +134,27 @@ function set_up() {
|
||||
},
|
||||
};
|
||||
|
||||
const pill_input = $.create("pill_input");
|
||||
const $pill_input = $.create("pill_input");
|
||||
|
||||
pill_input[0] = {};
|
||||
pill_input.before = () => {};
|
||||
$pill_input[0] = {};
|
||||
$pill_input.before = () => {};
|
||||
|
||||
const create_item_from_text = (text) => items[text];
|
||||
|
||||
const container = $.create("container");
|
||||
container.set_find_results(".input", pill_input);
|
||||
const $container = $.create("container");
|
||||
$container.set_find_results(".input", $pill_input);
|
||||
|
||||
const config = {
|
||||
container,
|
||||
$container,
|
||||
create_item_from_text,
|
||||
get_text_from_item: (item) => item.display_value,
|
||||
};
|
||||
|
||||
return {
|
||||
config,
|
||||
pill_input,
|
||||
$pill_input,
|
||||
items,
|
||||
container,
|
||||
$container,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -167,16 +167,16 @@ run_test("copy from pill", ({override_rewire, mock_template}) => {
|
||||
override_random_id({override_rewire});
|
||||
const info = set_up();
|
||||
const config = info.config;
|
||||
const container = info.container;
|
||||
const $container = info.$container;
|
||||
|
||||
const widget = input_pill.create(config);
|
||||
widget.appendValue("blue,red");
|
||||
|
||||
const copy_handler = container.get_on_handler("copy", ".pill");
|
||||
const copy_handler = $container.get_on_handler("copy", ".pill");
|
||||
|
||||
let copied_text;
|
||||
|
||||
const pill_stub = {
|
||||
const $pill_stub = {
|
||||
data: (field) => {
|
||||
assert.equal(field, "id");
|
||||
return "some_id2";
|
||||
@@ -195,7 +195,7 @@ run_test("copy from pill", ({override_rewire, mock_template}) => {
|
||||
preventDefault: noop,
|
||||
};
|
||||
|
||||
container.set_find_results(":focus", pill_stub);
|
||||
$container.set_find_results(":focus", $pill_stub);
|
||||
|
||||
copy_handler(e);
|
||||
|
||||
@@ -210,12 +210,12 @@ run_test("paste to input", ({mock_template}) => {
|
||||
|
||||
const info = set_up();
|
||||
const config = info.config;
|
||||
const container = info.container;
|
||||
const $container = info.$container;
|
||||
const items = info.items;
|
||||
|
||||
const widget = input_pill.create(config);
|
||||
|
||||
const paste_handler = container.get_on_handler("paste", ".input");
|
||||
const paste_handler = $container.get_on_handler("paste", ".input");
|
||||
|
||||
const paste_text = "blue,yellow";
|
||||
|
||||
@@ -233,7 +233,7 @@ run_test("paste to input", ({mock_template}) => {
|
||||
|
||||
document.execCommand = (cmd, _, text) => {
|
||||
assert.equal(cmd, "insertText");
|
||||
container.find(".input").text(text);
|
||||
$container.find(".input").text(text);
|
||||
};
|
||||
|
||||
paste_handler(e);
|
||||
@@ -257,12 +257,12 @@ run_test("arrows on pills", ({mock_template}) => {
|
||||
|
||||
const info = set_up();
|
||||
const config = info.config;
|
||||
const container = info.container;
|
||||
const $container = info.$container;
|
||||
|
||||
const widget = input_pill.create(config);
|
||||
widget.appendValue("blue,red");
|
||||
|
||||
const key_handler = container.get_on_handler("keydown", ".pill");
|
||||
const key_handler = $container.get_on_handler("keydown", ".pill");
|
||||
|
||||
function test_key(c) {
|
||||
key_handler({
|
||||
@@ -273,7 +273,7 @@ run_test("arrows on pills", ({mock_template}) => {
|
||||
let prev_focused = false;
|
||||
let next_focused = false;
|
||||
|
||||
const pill_stub = {
|
||||
const $pill_stub = {
|
||||
prev: () => ({
|
||||
trigger: (type) => {
|
||||
if (type === "focus") {
|
||||
@@ -290,7 +290,7 @@ run_test("arrows on pills", ({mock_template}) => {
|
||||
}),
|
||||
};
|
||||
|
||||
container.set_find_results(".pill:focus", pill_stub);
|
||||
$container.set_find_results(".pill:focus", $pill_stub);
|
||||
|
||||
// We use the same stub to test both arrows, since we don't
|
||||
// actually cause any real state changes here. We stub out
|
||||
@@ -310,16 +310,16 @@ run_test("left arrow on input", ({mock_template}) => {
|
||||
|
||||
const info = set_up();
|
||||
const config = info.config;
|
||||
const container = info.container;
|
||||
const $container = info.$container;
|
||||
|
||||
const widget = input_pill.create(config);
|
||||
widget.appendValue("blue,red");
|
||||
|
||||
const key_handler = container.get_on_handler("keydown", ".input");
|
||||
const key_handler = $container.get_on_handler("keydown", ".input");
|
||||
|
||||
let last_pill_focused = false;
|
||||
|
||||
container.set_find_results(".pill", {
|
||||
$container.set_find_results(".pill", {
|
||||
last: () => ({
|
||||
trigger: (type) => {
|
||||
if (type === "focus") {
|
||||
@@ -345,17 +345,17 @@ run_test("comma", ({mock_template}) => {
|
||||
const info = set_up();
|
||||
const config = info.config;
|
||||
const items = info.items;
|
||||
const pill_input = info.pill_input;
|
||||
const container = info.container;
|
||||
const $pill_input = info.$pill_input;
|
||||
const $container = info.$container;
|
||||
|
||||
const widget = input_pill.create(config);
|
||||
widget.appendValue("blue,red");
|
||||
|
||||
assert.deepEqual(widget.items(), [items.blue, items.red]);
|
||||
|
||||
const key_handler = container.get_on_handler("keydown", ".input");
|
||||
const key_handler = $container.get_on_handler("keydown", ".input");
|
||||
|
||||
pill_input.text(" yel");
|
||||
$pill_input.text(" yel");
|
||||
|
||||
key_handler({
|
||||
key: ",",
|
||||
@@ -364,7 +364,7 @@ run_test("comma", ({mock_template}) => {
|
||||
|
||||
assert.deepEqual(widget.items(), [items.blue, items.red]);
|
||||
|
||||
pill_input.text(" yellow");
|
||||
$pill_input.text(" yellow");
|
||||
|
||||
key_handler({
|
||||
key: ",",
|
||||
@@ -383,14 +383,14 @@ run_test("Enter key with text", ({mock_template}) => {
|
||||
const info = set_up();
|
||||
const config = info.config;
|
||||
const items = info.items;
|
||||
const container = info.container;
|
||||
const $container = info.$container;
|
||||
|
||||
const widget = input_pill.create(config);
|
||||
widget.appendValue("blue,red");
|
||||
|
||||
assert.deepEqual(widget.items(), [items.blue, items.red]);
|
||||
|
||||
const key_handler = container.get_on_handler("keydown", ".input");
|
||||
const key_handler = $container.get_on_handler("keydown", ".input");
|
||||
|
||||
key_handler({
|
||||
key: "Enter",
|
||||
@@ -415,13 +415,13 @@ run_test("insert_remove", ({override_rewire, mock_template}) => {
|
||||
const info = set_up();
|
||||
|
||||
const config = info.config;
|
||||
const pill_input = info.pill_input;
|
||||
const $pill_input = info.$pill_input;
|
||||
const items = info.items;
|
||||
const container = info.container;
|
||||
const $container = info.$container;
|
||||
|
||||
const inserted_html = [];
|
||||
pill_input.before = (elem) => {
|
||||
inserted_html.push(elem.html());
|
||||
$pill_input.before = ($elem) => {
|
||||
inserted_html.push($elem.html());
|
||||
};
|
||||
|
||||
const widget = input_pill.create(config);
|
||||
@@ -450,11 +450,11 @@ run_test("insert_remove", ({override_rewire, mock_template}) => {
|
||||
|
||||
assert.deepEqual(widget.items(), [items.blue, items.red, items.yellow]);
|
||||
|
||||
assert.equal(pill_input.text(), "chartreuse, mauve");
|
||||
assert.equal($pill_input.text(), "chartreuse, mauve");
|
||||
|
||||
assert.equal(widget.is_pending(), true);
|
||||
widget.clear_text();
|
||||
assert.equal(pill_input.text(), "");
|
||||
assert.equal($pill_input.text(), "");
|
||||
assert.equal(widget.is_pending(), false);
|
||||
|
||||
let color_removed;
|
||||
@@ -469,7 +469,7 @@ run_test("insert_remove", ({override_rewire, mock_template}) => {
|
||||
pill.$element.remove = set_colored_removed_func(pill.item.display_value);
|
||||
}
|
||||
|
||||
let key_handler = container.get_on_handler("keydown", ".input");
|
||||
let key_handler = $container.get_on_handler("keydown", ".input");
|
||||
|
||||
key_handler({
|
||||
key: "Backspace",
|
||||
@@ -486,7 +486,7 @@ run_test("insert_remove", ({override_rewire, mock_template}) => {
|
||||
|
||||
let next_pill_focused = false;
|
||||
|
||||
const next_pill_stub = {
|
||||
const $next_pill_stub = {
|
||||
trigger: (type) => {
|
||||
if (type === "focus") {
|
||||
next_pill_focused = true;
|
||||
@@ -494,17 +494,17 @@ run_test("insert_remove", ({override_rewire, mock_template}) => {
|
||||
},
|
||||
};
|
||||
|
||||
const focus_pill_stub = {
|
||||
next: () => next_pill_stub,
|
||||
const $focus_pill_stub = {
|
||||
next: () => $next_pill_stub,
|
||||
data: (field) => {
|
||||
assert.equal(field, "id");
|
||||
return "some_id1";
|
||||
},
|
||||
};
|
||||
|
||||
container.set_find_results(".pill:focus", focus_pill_stub);
|
||||
$container.set_find_results(".pill:focus", $focus_pill_stub);
|
||||
|
||||
key_handler = container.get_on_handler("keydown", ".pill");
|
||||
key_handler = $container.get_on_handler("keydown", ".pill");
|
||||
key_handler({
|
||||
key: "Backspace",
|
||||
preventDefault: noop,
|
||||
@@ -526,7 +526,7 @@ run_test("exit button on pill", ({override_rewire, mock_template}) => {
|
||||
|
||||
const config = info.config;
|
||||
const items = info.items;
|
||||
const container = info.container;
|
||||
const $container = info.$container;
|
||||
|
||||
const widget = input_pill.create(config);
|
||||
|
||||
@@ -539,7 +539,7 @@ run_test("exit button on pill", ({override_rewire, mock_template}) => {
|
||||
|
||||
let next_pill_focused = false;
|
||||
|
||||
const next_pill_stub = {
|
||||
const $next_pill_stub = {
|
||||
trigger: (type) => {
|
||||
if (type === "focus") {
|
||||
next_pill_focused = true;
|
||||
@@ -547,8 +547,8 @@ run_test("exit button on pill", ({override_rewire, mock_template}) => {
|
||||
},
|
||||
};
|
||||
|
||||
const curr_pill_stub = {
|
||||
next: () => next_pill_stub,
|
||||
const $curr_pill_stub = {
|
||||
next: () => $next_pill_stub,
|
||||
data: (field) => {
|
||||
assert.equal(field, "id");
|
||||
return "some_id1";
|
||||
@@ -559,7 +559,7 @@ run_test("exit button on pill", ({override_rewire, mock_template}) => {
|
||||
to_$: () => ({
|
||||
closest: (sel) => {
|
||||
assert.equal(sel, ".pill");
|
||||
return curr_pill_stub;
|
||||
return $curr_pill_stub;
|
||||
},
|
||||
}),
|
||||
};
|
||||
@@ -567,7 +567,7 @@ run_test("exit button on pill", ({override_rewire, mock_template}) => {
|
||||
const e = {
|
||||
stopPropagation: noop,
|
||||
};
|
||||
const exit_click_handler = container.get_on_handler("click", ".exit");
|
||||
const exit_click_handler = $container.get_on_handler("click", ".exit");
|
||||
|
||||
exit_click_handler.call(exit_button_stub, e);
|
||||
|
||||
@@ -580,13 +580,13 @@ run_test("misc things", () => {
|
||||
const info = set_up();
|
||||
|
||||
const config = info.config;
|
||||
const container = info.container;
|
||||
const pill_input = info.pill_input;
|
||||
const $container = info.$container;
|
||||
const $pill_input = info.$pill_input;
|
||||
|
||||
const widget = input_pill.create(config);
|
||||
|
||||
// animation
|
||||
const animation_end_handler = container.get_on_handler("animationend", ".input");
|
||||
const animation_end_handler = $container.get_on_handler("animationend", ".input");
|
||||
|
||||
let shake_class_removed = false;
|
||||
|
||||
@@ -614,17 +614,17 @@ run_test("misc things", () => {
|
||||
});
|
||||
|
||||
// click on container
|
||||
const container_click_handler = container.get_on_handler("click");
|
||||
const container_click_handler = $container.get_on_handler("click");
|
||||
|
||||
const stub = $.create("the-pill-container");
|
||||
stub.set_find_results(".input", pill_input);
|
||||
stub.is = (sel) => {
|
||||
const $stub = $.create("the-pill-container");
|
||||
$stub.set_find_results(".input", $pill_input);
|
||||
$stub.is = (sel) => {
|
||||
assert.equal(sel, ".pill-container");
|
||||
return true;
|
||||
};
|
||||
|
||||
const this_ = {
|
||||
to_$: () => stub,
|
||||
to_$: () => $stub,
|
||||
};
|
||||
|
||||
container_click_handler.call(this_, {target: this_});
|
||||
@@ -637,18 +637,18 @@ run_test("appendValue/clear", ({mock_template}) => {
|
||||
return html;
|
||||
});
|
||||
|
||||
const pill_input = $.create("pill_input");
|
||||
const container = $.create("container");
|
||||
container.set_find_results(".input", pill_input);
|
||||
const $pill_input = $.create("pill_input");
|
||||
const $container = $.create("container");
|
||||
$container.set_find_results(".input", $pill_input);
|
||||
|
||||
const config = {
|
||||
container,
|
||||
$container,
|
||||
create_item_from_text: (s) => ({type: "color", display_value: s}),
|
||||
get_text_from_item: (s) => s.display_value,
|
||||
};
|
||||
|
||||
pill_input.before = () => {};
|
||||
pill_input[0] = {};
|
||||
$pill_input.before = () => {};
|
||||
$pill_input[0] = {};
|
||||
|
||||
const widget = input_pill.create(config);
|
||||
|
||||
@@ -672,5 +672,5 @@ run_test("appendValue/clear", ({mock_template}) => {
|
||||
|
||||
// Note that we remove colors in the reverse order that we inserted.
|
||||
assert.deepEqual(removed_colors, ["blue", "yellow", "red"]);
|
||||
assert.equal(pill_input[0].textContent, "");
|
||||
assert.equal($pill_input[0].textContent, "");
|
||||
});
|
||||
|
||||
@@ -7,9 +7,9 @@ const $ = require("../zjsunit/zjquery");
|
||||
const keydown_util = zrequire("keydown_util");
|
||||
|
||||
run_test("test_early_returns", () => {
|
||||
const stub = $.create("stub");
|
||||
const $stub = $.create("stub");
|
||||
const opts = {
|
||||
elem: stub,
|
||||
$elem: $stub,
|
||||
handlers: {
|
||||
ArrowLeft: () => {
|
||||
throw new Error("do not dispatch this with alt key");
|
||||
@@ -24,14 +24,14 @@ run_test("test_early_returns", () => {
|
||||
key: "a", // not in keys
|
||||
};
|
||||
|
||||
stub.trigger(e1);
|
||||
$stub.trigger(e1);
|
||||
|
||||
const e2 = {
|
||||
type: "keydown",
|
||||
key: "Enter", // no handler
|
||||
};
|
||||
|
||||
stub.trigger(e2);
|
||||
$stub.trigger(e2);
|
||||
|
||||
const e3 = {
|
||||
type: "keydown",
|
||||
@@ -39,5 +39,5 @@ run_test("test_early_returns", () => {
|
||||
altKey: true, // let browser handle
|
||||
};
|
||||
|
||||
stub.trigger(e3);
|
||||
$stub.trigger(e3);
|
||||
});
|
||||
|
||||
@@ -30,21 +30,21 @@ function test(label, f) {
|
||||
}
|
||||
|
||||
test("pan_and_zoom", ({override_rewire}) => {
|
||||
const img = $.create("img-stub");
|
||||
const link = $.create("link-stub");
|
||||
const msg = $.create("msg-stub");
|
||||
const $img = $.create("img-stub");
|
||||
const $link = $.create("link-stub");
|
||||
const $msg = $.create("msg-stub");
|
||||
|
||||
$(img).closest = () => [];
|
||||
$($img).closest = () => [];
|
||||
|
||||
img.set_parent(link);
|
||||
link.closest = () => msg;
|
||||
$img.set_parent($link);
|
||||
$link.closest = () => $msg;
|
||||
|
||||
override_rewire(rows, "id", (row) => {
|
||||
assert.equal(row, msg);
|
||||
override_rewire(rows, "id", ($row) => {
|
||||
assert.equal($row, $msg);
|
||||
return 1234;
|
||||
});
|
||||
|
||||
img.attr("src", "example");
|
||||
$img.attr("src", "example");
|
||||
|
||||
let fetched_zid;
|
||||
|
||||
@@ -55,25 +55,25 @@ test("pan_and_zoom", ({override_rewire}) => {
|
||||
|
||||
override_rewire(lightbox, "render_lightbox_list_images", () => {});
|
||||
const open_image = lightbox.build_open_image_function();
|
||||
open_image(img);
|
||||
open_image($img);
|
||||
|
||||
assert.equal(fetched_zid, 1234);
|
||||
});
|
||||
|
||||
test("youtube", ({override_rewire}) => {
|
||||
const href = "https://youtube.com/some-random-clip";
|
||||
const img = $.create("img-stub");
|
||||
const link = $.create("link-stub");
|
||||
const msg = $.create("msg-stub");
|
||||
const $img = $.create("img-stub");
|
||||
const $link = $.create("link-stub");
|
||||
const $msg = $.create("msg-stub");
|
||||
|
||||
override_rewire(rows, "id", (row) => {
|
||||
assert.equal(row, msg);
|
||||
override_rewire(rows, "id", ($row) => {
|
||||
assert.equal($row, $msg);
|
||||
return 4321;
|
||||
});
|
||||
|
||||
$(img).attr("src", href);
|
||||
$($img).attr("src", href);
|
||||
|
||||
$(img).closest = (sel) => {
|
||||
$($img).closest = (sel) => {
|
||||
if (sel === ".youtube-video") {
|
||||
// We just need a nonempty array to
|
||||
// set is_youtube_video to true.
|
||||
@@ -82,13 +82,13 @@ test("youtube", ({override_rewire}) => {
|
||||
return [];
|
||||
};
|
||||
|
||||
img.set_parent(link);
|
||||
link.closest = () => msg;
|
||||
link.attr("href", href);
|
||||
$img.set_parent($link);
|
||||
$link.closest = () => $msg;
|
||||
$link.attr("href", href);
|
||||
|
||||
override_rewire(lightbox, "render_lightbox_list_images", () => {});
|
||||
|
||||
const open_image = lightbox.build_open_image_function();
|
||||
open_image(img);
|
||||
open_image($img);
|
||||
assert.equal($(".image-actions .open").attr("href"), href);
|
||||
});
|
||||
|
||||
@@ -70,12 +70,12 @@ run_test("single item list", ({override}) => {
|
||||
});
|
||||
const cursor = new ListCursor(conf);
|
||||
|
||||
const li_stub = {
|
||||
const $li_stub = {
|
||||
length: 1,
|
||||
addClass: () => {},
|
||||
};
|
||||
|
||||
override(conf.list, "find_li", () => li_stub);
|
||||
override(conf.list, "find_li", () => $li_stub);
|
||||
override(cursor, "adjust_scroll", () => {});
|
||||
|
||||
cursor.go_to(valid_key);
|
||||
|
||||
@@ -41,81 +41,81 @@ const ListWidget = zrequire("list_widget");
|
||||
// in the real code.
|
||||
|
||||
function make_container() {
|
||||
const container = {};
|
||||
const $container = {};
|
||||
|
||||
container.length = () => 1;
|
||||
container.is = () => false;
|
||||
container.css = (prop) => {
|
||||
$container.length = () => 1;
|
||||
$container.is = () => false;
|
||||
$container.css = (prop) => {
|
||||
assert.equal(prop, "max-height");
|
||||
return "none";
|
||||
};
|
||||
|
||||
// Make our append function just set a field we can
|
||||
// check in our tests.
|
||||
container.append = (data) => {
|
||||
container.appended_data = data;
|
||||
$container.append = ($data) => {
|
||||
$container.$appended_data = $data;
|
||||
};
|
||||
|
||||
return container;
|
||||
return $container;
|
||||
}
|
||||
|
||||
function make_scroll_container() {
|
||||
const scroll_container = {};
|
||||
const $scroll_container = {};
|
||||
|
||||
scroll_container.cleared = false;
|
||||
$scroll_container.cleared = false;
|
||||
|
||||
// Capture the scroll callback so we can call it in
|
||||
// our tests.
|
||||
scroll_container.on = (ev, f) => {
|
||||
$scroll_container.on = (ev, f) => {
|
||||
assert.equal(ev, "scroll.list_widget_container");
|
||||
scroll_container.call_scroll = () => {
|
||||
f.call(scroll_container);
|
||||
$scroll_container.call_scroll = () => {
|
||||
f.call($scroll_container);
|
||||
};
|
||||
};
|
||||
|
||||
scroll_container.off = (ev) => {
|
||||
$scroll_container.off = (ev) => {
|
||||
assert.equal(ev, "scroll.list_widget_container");
|
||||
scroll_container.cleared = true;
|
||||
$scroll_container.cleared = true;
|
||||
};
|
||||
|
||||
return scroll_container;
|
||||
return $scroll_container;
|
||||
}
|
||||
|
||||
function make_sort_container() {
|
||||
const sort_container = {};
|
||||
const $sort_container = {};
|
||||
|
||||
sort_container.cleared = false;
|
||||
$sort_container.cleared = false;
|
||||
|
||||
sort_container.on = (ev, sel, f) => {
|
||||
$sort_container.on = (ev, sel, f) => {
|
||||
assert.equal(ev, "click.list_widget_sort");
|
||||
assert.equal(sel, "[data-sort]");
|
||||
sort_container.f = f;
|
||||
$sort_container.f = f;
|
||||
};
|
||||
|
||||
sort_container.off = (ev) => {
|
||||
$sort_container.off = (ev) => {
|
||||
assert.equal(ev, "click.list_widget_sort");
|
||||
sort_container.cleared = true;
|
||||
$sort_container.cleared = true;
|
||||
};
|
||||
|
||||
return sort_container;
|
||||
return $sort_container;
|
||||
}
|
||||
|
||||
function make_filter_element() {
|
||||
const element = {};
|
||||
const $element = {};
|
||||
|
||||
element.cleared = false;
|
||||
$element.cleared = false;
|
||||
|
||||
element.on = (ev, f) => {
|
||||
$element.on = (ev, f) => {
|
||||
assert.equal(ev, "input.list_widget_filter");
|
||||
element.f = f;
|
||||
$element.f = f;
|
||||
};
|
||||
|
||||
element.off = (ev) => {
|
||||
$element.off = (ev) => {
|
||||
assert.equal(ev, "input.list_widget_filter");
|
||||
element.cleared = true;
|
||||
$element.cleared = true;
|
||||
};
|
||||
|
||||
return element;
|
||||
return $element;
|
||||
}
|
||||
|
||||
function make_search_input() {
|
||||
@@ -143,15 +143,15 @@ function div(item) {
|
||||
}
|
||||
|
||||
run_test("scrolling", () => {
|
||||
const container = make_container();
|
||||
const scroll_container = make_scroll_container();
|
||||
const $container = make_container();
|
||||
const $scroll_container = make_scroll_container();
|
||||
|
||||
const items = [];
|
||||
|
||||
let get_scroll_element_called = false;
|
||||
ui.get_scroll_element = (element) => {
|
||||
ui.get_scroll_element = ($element) => {
|
||||
get_scroll_element_called = true;
|
||||
return element;
|
||||
return $element;
|
||||
};
|
||||
|
||||
for (let i = 0; i < 200; i += 1) {
|
||||
@@ -160,38 +160,38 @@ run_test("scrolling", () => {
|
||||
|
||||
const opts = {
|
||||
modifier: (item) => item,
|
||||
simplebar_container: scroll_container,
|
||||
$simplebar_container: $scroll_container,
|
||||
};
|
||||
|
||||
container.html = (html) => {
|
||||
$container.html = (html) => {
|
||||
assert.equal(html, "");
|
||||
};
|
||||
ListWidget.create(container, items, opts);
|
||||
ListWidget.create($container, items, opts);
|
||||
|
||||
assert.deepEqual(container.appended_data.html(), items.slice(0, 80).join(""));
|
||||
assert.deepEqual($container.$appended_data.html(), items.slice(0, 80).join(""));
|
||||
assert.equal(get_scroll_element_called, true);
|
||||
|
||||
// Set up our fake geometry so it forces a scroll action.
|
||||
scroll_container.scrollTop = 180;
|
||||
scroll_container.clientHeight = 100;
|
||||
scroll_container.scrollHeight = 260;
|
||||
$scroll_container.scrollTop = 180;
|
||||
$scroll_container.clientHeight = 100;
|
||||
$scroll_container.scrollHeight = 260;
|
||||
|
||||
// Scrolling gets the next two elements from the list into
|
||||
// our widget.
|
||||
scroll_container.call_scroll();
|
||||
assert.deepEqual(container.appended_data.html(), items.slice(80, 100).join(""));
|
||||
$scroll_container.call_scroll();
|
||||
assert.deepEqual($container.$appended_data.html(), items.slice(80, 100).join(""));
|
||||
});
|
||||
|
||||
run_test("not_scrolling", () => {
|
||||
const container = make_container();
|
||||
const scroll_container = make_scroll_container();
|
||||
const $container = make_container();
|
||||
const $scroll_container = make_scroll_container();
|
||||
|
||||
const items = [];
|
||||
|
||||
let get_scroll_element_called = false;
|
||||
ui.get_scroll_element = (element) => {
|
||||
ui.get_scroll_element = ($element) => {
|
||||
get_scroll_element_called = true;
|
||||
return element;
|
||||
return $element;
|
||||
};
|
||||
|
||||
let post_scroll__pre_render_callback_called = false;
|
||||
@@ -211,54 +211,54 @@ run_test("not_scrolling", () => {
|
||||
|
||||
const opts = {
|
||||
modifier: (item) => item,
|
||||
simplebar_container: scroll_container,
|
||||
$simplebar_container: $scroll_container,
|
||||
is_scroll_position_for_render: () => false,
|
||||
post_scroll__pre_render_callback,
|
||||
get_min_load_count,
|
||||
};
|
||||
|
||||
container.html = (html) => {
|
||||
$container.html = (html) => {
|
||||
assert.equal(html, "");
|
||||
};
|
||||
ListWidget.create(container, items, opts);
|
||||
ListWidget.create($container, items, opts);
|
||||
|
||||
assert.deepEqual(container.appended_data.html(), items.slice(0, 80).join(""));
|
||||
assert.deepEqual($container.$appended_data.html(), items.slice(0, 80).join(""));
|
||||
assert.equal(get_scroll_element_called, true);
|
||||
|
||||
// Set up our fake geometry.
|
||||
scroll_container.scrollTop = 180;
|
||||
scroll_container.clientHeight = 100;
|
||||
scroll_container.scrollHeight = 260;
|
||||
$scroll_container.scrollTop = 180;
|
||||
$scroll_container.clientHeight = 100;
|
||||
$scroll_container.scrollHeight = 260;
|
||||
|
||||
// Since `should_render` is always false, no elements will be
|
||||
// added regardless of scrolling.
|
||||
scroll_container.call_scroll();
|
||||
// appended_data remains the same.
|
||||
assert.deepEqual(container.appended_data.html(), items.slice(0, 80).join(""));
|
||||
$scroll_container.call_scroll();
|
||||
// $appended_data remains the same.
|
||||
assert.deepEqual($container.$appended_data.html(), items.slice(0, 80).join(""));
|
||||
assert.equal(post_scroll__pre_render_callback_called, true);
|
||||
assert.equal(get_min_load_count_called, true);
|
||||
});
|
||||
|
||||
run_test("filtering", () => {
|
||||
const container = make_container();
|
||||
const scroll_container = make_scroll_container();
|
||||
const $container = make_container();
|
||||
const $scroll_container = make_scroll_container();
|
||||
|
||||
const search_input = make_search_input();
|
||||
const $search_input = make_search_input();
|
||||
|
||||
const list = ["apple", "banana", "carrot", "dog", "egg", "fence", "grape"];
|
||||
const opts = {
|
||||
filter: {
|
||||
element: search_input,
|
||||
$element: $search_input,
|
||||
predicate: (item, value) => item.includes(value),
|
||||
},
|
||||
modifier: (item) => div(item),
|
||||
simplebar_container: scroll_container,
|
||||
$simplebar_container: $scroll_container,
|
||||
};
|
||||
|
||||
container.html = (html) => {
|
||||
$container.html = (html) => {
|
||||
assert.equal(html, "");
|
||||
};
|
||||
const widget = ListWidget.create(container, list, opts);
|
||||
const widget = ListWidget.create($container, list, opts);
|
||||
|
||||
let expected_html =
|
||||
"<div>apple</div>" +
|
||||
@@ -269,45 +269,45 @@ run_test("filtering", () => {
|
||||
"<div>fence</div>" +
|
||||
"<div>grape</div>";
|
||||
|
||||
assert.deepEqual(container.appended_data.html(), expected_html);
|
||||
assert.deepEqual($container.$appended_data.html(), expected_html);
|
||||
|
||||
// Filtering will pick out dog/egg/grape when we put "g"
|
||||
// into our search input. (This uses the default filter, which
|
||||
// is a glorified indexOf call.)
|
||||
search_input.val = () => "g";
|
||||
search_input.simulate_input_event();
|
||||
$search_input.val = () => "g";
|
||||
$search_input.simulate_input_event();
|
||||
assert.deepEqual(widget.get_current_list(), ["dog", "egg", "grape"]);
|
||||
expected_html = "<div>dog</div><div>egg</div><div>grape</div>";
|
||||
assert.deepEqual(container.appended_data.html(), expected_html);
|
||||
assert.deepEqual($container.$appended_data.html(), expected_html);
|
||||
|
||||
// We can insert new data into the widget.
|
||||
const new_data = ["greta", "faye", "gary", "frank", "giraffe", "fox"];
|
||||
|
||||
widget.replace_list_data(new_data);
|
||||
expected_html = "<div>greta</div><div>gary</div><div>giraffe</div>";
|
||||
assert.deepEqual(container.appended_data.html(), expected_html);
|
||||
assert.deepEqual($container.$appended_data.html(), expected_html);
|
||||
});
|
||||
|
||||
run_test("no filtering", () => {
|
||||
const container = make_container();
|
||||
const scroll_container = make_scroll_container();
|
||||
container.html = () => {};
|
||||
const $container = make_container();
|
||||
const $scroll_container = make_scroll_container();
|
||||
$container.html = () => {};
|
||||
|
||||
let callback_called = false;
|
||||
// Opts does not require a filter key.
|
||||
const opts = {
|
||||
modifier: (item) => div(item),
|
||||
simplebar_container: scroll_container,
|
||||
$simplebar_container: $scroll_container,
|
||||
callback_after_render: () => {
|
||||
callback_called = true;
|
||||
},
|
||||
};
|
||||
const widget = ListWidget.create(container, ["apple", "banana"], opts);
|
||||
const widget = ListWidget.create($container, ["apple", "banana"], opts);
|
||||
widget.render();
|
||||
assert.deepEqual(callback_called, true);
|
||||
|
||||
const expected_html = "<div>apple</div><div>banana</div>";
|
||||
assert.deepEqual(container.appended_data.html(), expected_html);
|
||||
assert.deepEqual($container.$appended_data.html(), expected_html);
|
||||
});
|
||||
|
||||
function sort_button(opts) {
|
||||
@@ -336,7 +336,7 @@ function sort_button(opts) {
|
||||
|
||||
const classList = new Set();
|
||||
|
||||
const button = {
|
||||
const $button = {
|
||||
data,
|
||||
closest: lookup(".progressive-table-wrapper", {
|
||||
data: lookup("list-widget", opts.list_name),
|
||||
@@ -351,47 +351,47 @@ function sort_button(opts) {
|
||||
siblings: lookup(".active", {
|
||||
removeClass: (cls) => {
|
||||
assert.equal(cls, "active");
|
||||
button.siblings_deactivated = true;
|
||||
$button.siblings_deactivated = true;
|
||||
},
|
||||
}),
|
||||
siblings_deactivated: false,
|
||||
to_jquery: () => button,
|
||||
to_jquery: () => $button,
|
||||
};
|
||||
|
||||
return button;
|
||||
return $button;
|
||||
}
|
||||
|
||||
run_test("wire up filter element", () => {
|
||||
const lst = ["alice", "JESSE", "moses", "scott", "Sean", "Xavier"];
|
||||
|
||||
const container = make_container();
|
||||
const scroll_container = make_scroll_container();
|
||||
const filter_element = make_filter_element();
|
||||
const $container = make_container();
|
||||
const $scroll_container = make_scroll_container();
|
||||
const $filter_element = make_filter_element();
|
||||
|
||||
// We don't care about what gets drawn initially.
|
||||
container.html = () => {};
|
||||
$container.html = () => {};
|
||||
|
||||
const opts = {
|
||||
filter: {
|
||||
filterer: (list, value) => list.filter((item) => item.toLowerCase().includes(value)),
|
||||
element: filter_element,
|
||||
$element: $filter_element,
|
||||
},
|
||||
modifier: (s) => "(" + s + ")",
|
||||
simplebar_container: scroll_container,
|
||||
$simplebar_container: $scroll_container,
|
||||
};
|
||||
|
||||
ListWidget.create(container, lst, opts);
|
||||
filter_element.f.apply({value: "se"});
|
||||
assert.equal(container.appended_data.html(), "(JESSE)(moses)(Sean)");
|
||||
ListWidget.create($container, lst, opts);
|
||||
$filter_element.f.apply({value: "se"});
|
||||
assert.equal($container.$appended_data.html(), "(JESSE)(moses)(Sean)");
|
||||
});
|
||||
|
||||
run_test("sorting", () => {
|
||||
const container = make_container();
|
||||
const scroll_container = make_scroll_container();
|
||||
const sort_container = make_sort_container();
|
||||
const $container = make_container();
|
||||
const $scroll_container = make_scroll_container();
|
||||
const $sort_container = make_sort_container();
|
||||
|
||||
let cleared;
|
||||
container.html = (html) => {
|
||||
$container.html = (html) => {
|
||||
assert.equal(html, "");
|
||||
cleared = true;
|
||||
};
|
||||
@@ -406,22 +406,22 @@ run_test("sorting", () => {
|
||||
|
||||
const opts = {
|
||||
name: "sorting-list",
|
||||
parent_container: sort_container,
|
||||
$parent_container: $sort_container,
|
||||
modifier: (item) => div(item.name) + div(item.salary),
|
||||
filter: {
|
||||
predicate: () => true,
|
||||
},
|
||||
simplebar_container: scroll_container,
|
||||
$simplebar_container: $scroll_container,
|
||||
};
|
||||
|
||||
function html_for(people) {
|
||||
return people.map((item) => opts.modifier(item)).join("");
|
||||
}
|
||||
|
||||
ListWidget.create(container, list, opts);
|
||||
ListWidget.create($container, list, opts);
|
||||
|
||||
let button_opts;
|
||||
let button;
|
||||
let $button;
|
||||
let expected_html;
|
||||
|
||||
button_opts = {
|
||||
@@ -431,31 +431,31 @@ run_test("sorting", () => {
|
||||
active: false,
|
||||
};
|
||||
|
||||
button = sort_button(button_opts);
|
||||
$button = sort_button(button_opts);
|
||||
|
||||
sort_container.f.apply(button);
|
||||
$sort_container.f.apply($button);
|
||||
|
||||
assert.ok(cleared);
|
||||
assert.ok(button.siblings_deactivated);
|
||||
assert.ok($button.siblings_deactivated);
|
||||
|
||||
expected_html = html_for([alice, bob, cal, dave, ellen]);
|
||||
assert.deepEqual(container.appended_data.html(), expected_html);
|
||||
assert.deepEqual($container.$appended_data.html(), expected_html);
|
||||
|
||||
// Hit same button again to reverse the data.
|
||||
cleared = false;
|
||||
sort_container.f.apply(button);
|
||||
$sort_container.f.apply($button);
|
||||
assert.ok(cleared);
|
||||
expected_html = html_for([ellen, dave, cal, bob, alice]);
|
||||
assert.deepEqual(container.appended_data.html(), expected_html);
|
||||
assert.ok(button.hasClass("descend"));
|
||||
assert.deepEqual($container.$appended_data.html(), expected_html);
|
||||
assert.ok($button.hasClass("descend"));
|
||||
|
||||
// And then hit a third time to go back to the forward sort.
|
||||
cleared = false;
|
||||
sort_container.f.apply(button);
|
||||
$sort_container.f.apply($button);
|
||||
assert.ok(cleared);
|
||||
expected_html = html_for([alice, bob, cal, dave, ellen]);
|
||||
assert.deepEqual(container.appended_data.html(), expected_html);
|
||||
assert.ok(!button.hasClass("descend"));
|
||||
assert.deepEqual($container.$appended_data.html(), expected_html);
|
||||
assert.ok(!$button.hasClass("descend"));
|
||||
|
||||
// Now try a numeric sort.
|
||||
button_opts = {
|
||||
@@ -465,32 +465,32 @@ run_test("sorting", () => {
|
||||
active: false,
|
||||
};
|
||||
|
||||
button = sort_button(button_opts);
|
||||
$button = sort_button(button_opts);
|
||||
|
||||
cleared = false;
|
||||
button.siblings_deactivated = false;
|
||||
$button.siblings_deactivated = false;
|
||||
|
||||
sort_container.f.apply(button);
|
||||
$sort_container.f.apply($button);
|
||||
|
||||
assert.ok(cleared);
|
||||
assert.ok(button.siblings_deactivated);
|
||||
assert.ok($button.siblings_deactivated);
|
||||
|
||||
expected_html = html_for([dave, cal, bob, alice, ellen]);
|
||||
assert.deepEqual(container.appended_data.html(), expected_html);
|
||||
assert.deepEqual($container.$appended_data.html(), expected_html);
|
||||
|
||||
// Hit same button again to reverse the numeric sort.
|
||||
cleared = false;
|
||||
sort_container.f.apply(button);
|
||||
$sort_container.f.apply($button);
|
||||
assert.ok(cleared);
|
||||
expected_html = html_for([ellen, alice, bob, cal, dave]);
|
||||
assert.deepEqual(container.appended_data.html(), expected_html);
|
||||
assert.ok(button.hasClass("descend"));
|
||||
assert.deepEqual($container.$appended_data.html(), expected_html);
|
||||
assert.ok($button.hasClass("descend"));
|
||||
});
|
||||
|
||||
run_test("custom sort", () => {
|
||||
const container = make_container();
|
||||
const scroll_container = make_scroll_container();
|
||||
container.html = () => {};
|
||||
const $container = make_container();
|
||||
const $scroll_container = make_scroll_container();
|
||||
$container.html = () => {};
|
||||
|
||||
const n42 = {x: 6, y: 7};
|
||||
const n43 = {x: 1, y: 43};
|
||||
@@ -506,7 +506,7 @@ run_test("custom sort", () => {
|
||||
return a.x * a.y - b.x * b.y;
|
||||
}
|
||||
|
||||
ListWidget.create(container, list, {
|
||||
ListWidget.create($container, list, {
|
||||
name: "custom-sort-list",
|
||||
modifier: (n) => "(" + n.x + ", " + n.y + ")",
|
||||
sort_fields: {
|
||||
@@ -514,15 +514,15 @@ run_test("custom sort", () => {
|
||||
x_value: sort_by_x,
|
||||
},
|
||||
init_sort: [sort_by_product],
|
||||
simplebar_container: scroll_container,
|
||||
$simplebar_container: $scroll_container,
|
||||
});
|
||||
|
||||
assert.deepEqual(container.appended_data.html(), "(6, 7)(1, 43)(4, 11)");
|
||||
assert.deepEqual($container.$appended_data.html(), "(6, 7)(1, 43)(4, 11)");
|
||||
|
||||
const widget = ListWidget.get("custom-sort-list");
|
||||
|
||||
widget.sort("x_value");
|
||||
assert.deepEqual(container.appended_data.html(), "(1, 43)(4, 11)(6, 7)");
|
||||
assert.deepEqual($container.$appended_data.html(), "(1, 43)(4, 11)(6, 7)");
|
||||
|
||||
// We can sort without registering the function, too.
|
||||
function sort_by_y(a, b) {
|
||||
@@ -530,97 +530,97 @@ run_test("custom sort", () => {
|
||||
}
|
||||
|
||||
widget.sort(sort_by_y);
|
||||
assert.deepEqual(container.appended_data.html(), "(6, 7)(4, 11)(1, 43)");
|
||||
assert.deepEqual($container.$appended_data.html(), "(6, 7)(4, 11)(1, 43)");
|
||||
});
|
||||
|
||||
run_test("clear_event_handlers", () => {
|
||||
const container = make_container();
|
||||
const scroll_container = make_scroll_container();
|
||||
const sort_container = make_sort_container();
|
||||
const filter_element = make_filter_element();
|
||||
const $container = make_container();
|
||||
const $scroll_container = make_scroll_container();
|
||||
const $sort_container = make_sort_container();
|
||||
const $filter_element = make_filter_element();
|
||||
|
||||
// We don't care about actual data for this test.
|
||||
const list = [];
|
||||
container.html = () => {};
|
||||
$container.html = () => {};
|
||||
|
||||
const opts = {
|
||||
name: "list-we-create-twice",
|
||||
parent_container: sort_container,
|
||||
$parent_container: $sort_container,
|
||||
modifier: () => {},
|
||||
filter: {
|
||||
element: filter_element,
|
||||
$element: $filter_element,
|
||||
predicate: () => true,
|
||||
},
|
||||
simplebar_container: scroll_container,
|
||||
$simplebar_container: $scroll_container,
|
||||
};
|
||||
|
||||
// Create it the first time.
|
||||
ListWidget.create(container, list, opts);
|
||||
assert.equal(sort_container.cleared, false);
|
||||
assert.equal(scroll_container.cleared, false);
|
||||
assert.equal(filter_element.cleared, false);
|
||||
ListWidget.create($container, list, opts);
|
||||
assert.equal($sort_container.cleared, false);
|
||||
assert.equal($scroll_container.cleared, false);
|
||||
assert.equal($filter_element.cleared, false);
|
||||
|
||||
// The second time we'll clear the old events.
|
||||
ListWidget.create(container, list, opts);
|
||||
assert.equal(sort_container.cleared, true);
|
||||
assert.equal(scroll_container.cleared, true);
|
||||
assert.equal(filter_element.cleared, true);
|
||||
ListWidget.create($container, list, opts);
|
||||
assert.equal($sort_container.cleared, true);
|
||||
assert.equal($scroll_container.cleared, true);
|
||||
assert.equal($filter_element.cleared, true);
|
||||
});
|
||||
|
||||
run_test("errors", () => {
|
||||
// We don't care about actual data for this test.
|
||||
const list = ["stub"];
|
||||
const container = make_container();
|
||||
const scroll_container = make_scroll_container();
|
||||
const $container = make_container();
|
||||
const $scroll_container = make_scroll_container();
|
||||
|
||||
blueslip.expect("error", "Need opts to create widget.");
|
||||
ListWidget.create(container, list);
|
||||
ListWidget.create($container, list);
|
||||
blueslip.reset();
|
||||
|
||||
blueslip.expect("error", "simplebar_container is missing.");
|
||||
ListWidget.create(container, list, {
|
||||
blueslip.expect("error", "$simplebar_container is missing.");
|
||||
ListWidget.create($container, list, {
|
||||
modifier: "hello world",
|
||||
});
|
||||
blueslip.reset();
|
||||
|
||||
blueslip.expect("error", "get_item should be a function");
|
||||
ListWidget.create(container, list, {
|
||||
ListWidget.create($container, list, {
|
||||
get_item: "not a function",
|
||||
simplebar_container: scroll_container,
|
||||
$simplebar_container: $scroll_container,
|
||||
});
|
||||
blueslip.reset();
|
||||
|
||||
blueslip.expect("error", "Filter predicate is not a function.");
|
||||
ListWidget.create(container, list, {
|
||||
ListWidget.create($container, list, {
|
||||
filter: {
|
||||
predicate: "wrong type",
|
||||
},
|
||||
simplebar_container: scroll_container,
|
||||
$simplebar_container: $scroll_container,
|
||||
});
|
||||
blueslip.reset();
|
||||
|
||||
blueslip.expect("error", "Filterer and predicate are mutually exclusive.");
|
||||
ListWidget.create(container, list, {
|
||||
ListWidget.create($container, list, {
|
||||
filter: {
|
||||
filterer: () => true,
|
||||
predicate: () => true,
|
||||
},
|
||||
simplebar_container: scroll_container,
|
||||
$simplebar_container: $scroll_container,
|
||||
});
|
||||
blueslip.reset();
|
||||
|
||||
blueslip.expect("error", "Filter filterer is not a function (or missing).");
|
||||
ListWidget.create(container, list, {
|
||||
ListWidget.create($container, list, {
|
||||
filter: {},
|
||||
simplebar_container: scroll_container,
|
||||
$simplebar_container: $scroll_container,
|
||||
});
|
||||
blueslip.reset();
|
||||
|
||||
container.html = () => {};
|
||||
$container.html = () => {};
|
||||
blueslip.expect("error", "List item is not a string: 999");
|
||||
ListWidget.create(container, list, {
|
||||
ListWidget.create($container, list, {
|
||||
modifier: () => 999,
|
||||
simplebar_container: scroll_container,
|
||||
$simplebar_container: $scroll_container,
|
||||
});
|
||||
blueslip.reset();
|
||||
});
|
||||
@@ -648,14 +648,14 @@ run_test("sort helpers", () => {
|
||||
});
|
||||
|
||||
run_test("replace_list_data w/filter update", () => {
|
||||
const container = make_container();
|
||||
const scroll_container = make_scroll_container();
|
||||
container.html = () => {};
|
||||
const $container = make_container();
|
||||
const $scroll_container = make_scroll_container();
|
||||
$container.html = () => {};
|
||||
|
||||
const list = [1, 2, 3, 4];
|
||||
let num_updates = 0;
|
||||
|
||||
ListWidget.create(container, list, {
|
||||
ListWidget.create($container, list, {
|
||||
name: "replace-list",
|
||||
modifier: (n) => "(" + n.toString() + ")",
|
||||
filter: {
|
||||
@@ -664,19 +664,19 @@ run_test("replace_list_data w/filter update", () => {
|
||||
num_updates += 1;
|
||||
},
|
||||
},
|
||||
simplebar_container: scroll_container,
|
||||
$simplebar_container: $scroll_container,
|
||||
});
|
||||
|
||||
assert.equal(num_updates, 0);
|
||||
|
||||
assert.deepEqual(container.appended_data.html(), "(2)(4)");
|
||||
assert.deepEqual($container.$appended_data.html(), "(2)(4)");
|
||||
|
||||
const widget = ListWidget.get("replace-list");
|
||||
widget.replace_list_data([5, 6, 7, 8]);
|
||||
|
||||
assert.equal(num_updates, 1);
|
||||
|
||||
assert.deepEqual(container.appended_data.html(), "(6)(8)");
|
||||
assert.deepEqual($container.$appended_data.html(), "(6)(8)");
|
||||
});
|
||||
|
||||
run_test("opts.get_item", () => {
|
||||
@@ -722,12 +722,12 @@ run_test("opts.get_item", () => {
|
||||
});
|
||||
|
||||
run_test("render item", () => {
|
||||
const container = make_container();
|
||||
const scroll_container = make_scroll_container();
|
||||
const $container = make_container();
|
||||
const $scroll_container = make_scroll_container();
|
||||
const INITIAL_RENDER_COUNT = 80; // Keep this in sync with the actual code.
|
||||
container.html = () => {};
|
||||
$container.html = () => {};
|
||||
let called = false;
|
||||
scroll_container.find = (query) => {
|
||||
$scroll_container.find = (query) => {
|
||||
const expected_queries = [
|
||||
`tr[data-item='${INITIAL_RENDER_COUNT}']`,
|
||||
`tr[data-item='${INITIAL_RENDER_COUNT - 1}']`,
|
||||
@@ -746,7 +746,7 @@ run_test("render item", () => {
|
||||
replaceWith: (html) => {
|
||||
assert.equal(new_html, html);
|
||||
called = true;
|
||||
container.appended_data.replace(regex, new_html);
|
||||
$container.$appended_data.replace(regex, new_html);
|
||||
},
|
||||
};
|
||||
};
|
||||
@@ -756,29 +756,29 @@ run_test("render item", () => {
|
||||
let text = "initial";
|
||||
const get_item = (item) => ({text: `${text}: ${item}`, value: item});
|
||||
|
||||
const widget = ListWidget.create(container, list, {
|
||||
const widget = ListWidget.create($container, list, {
|
||||
name: "replace-list",
|
||||
modifier: (item) => `<tr data-item=${item.value}>${item.text}</tr>\n`,
|
||||
get_item,
|
||||
html_selector: (item) => `tr[data-item='${item}']`,
|
||||
simplebar_container: scroll_container,
|
||||
$simplebar_container: $scroll_container,
|
||||
});
|
||||
const item = INITIAL_RENDER_COUNT - 1;
|
||||
|
||||
assert.ok(container.appended_data.html().includes("<tr data-item=2>initial: 2</tr>"));
|
||||
assert.ok(container.appended_data.html().includes("<tr data-item=3>initial: 3</tr>"));
|
||||
assert.ok($container.$appended_data.html().includes("<tr data-item=2>initial: 2</tr>"));
|
||||
assert.ok($container.$appended_data.html().includes("<tr data-item=3>initial: 3</tr>"));
|
||||
text = "updated";
|
||||
called = false;
|
||||
widget.render_item(INITIAL_RENDER_COUNT - 1);
|
||||
assert.ok(called);
|
||||
assert.ok(container.appended_data.html().includes("<tr data-item=2>initial: 2</tr>"));
|
||||
assert.ok($container.$appended_data.html().includes("<tr data-item=2>initial: 2</tr>"));
|
||||
assert.ok(
|
||||
container.appended_data.html().includes(`<tr data-item=${item}>updated: ${item}</tr>`),
|
||||
$container.$appended_data.html().includes(`<tr data-item=${item}>updated: ${item}</tr>`),
|
||||
);
|
||||
|
||||
// Item 80 should not be in the rendered list. (0 indexed)
|
||||
assert.ok(
|
||||
!container.appended_data
|
||||
!$container.$appended_data
|
||||
.html()
|
||||
.includes(
|
||||
`<tr data-item=${INITIAL_RENDER_COUNT}>initial: ${INITIAL_RENDER_COUNT}</tr>`,
|
||||
@@ -793,24 +793,24 @@ run_test("render item", () => {
|
||||
// Tests below this are for the corner cases, where we abort the rerender.
|
||||
|
||||
blueslip.expect("error", "html_selector should be a function.");
|
||||
ListWidget.create(container, list, {
|
||||
ListWidget.create($container, list, {
|
||||
name: "replace-list",
|
||||
modifier: (item) => `<tr data-item=${item.value}>${item.text}</tr>\n`,
|
||||
get_item,
|
||||
html_selector: "hello world",
|
||||
simplebar_container: scroll_container,
|
||||
$simplebar_container: $scroll_container,
|
||||
});
|
||||
blueslip.reset();
|
||||
|
||||
let get_item_called;
|
||||
const widget_2 = ListWidget.create(container, list, {
|
||||
const widget_2 = ListWidget.create($container, list, {
|
||||
name: "replace-list",
|
||||
modifier: (item) => `<tr data-item=${item.value}>${item.text}</tr>\n`,
|
||||
get_item: (item) => {
|
||||
get_item_called = true;
|
||||
return item;
|
||||
},
|
||||
simplebar_container: scroll_container,
|
||||
$simplebar_container: $scroll_container,
|
||||
});
|
||||
get_item_called = false;
|
||||
widget_2.render_item(item);
|
||||
@@ -818,12 +818,12 @@ run_test("render item", () => {
|
||||
assert.ok(!get_item_called);
|
||||
|
||||
let rendering_item = false;
|
||||
const widget_3 = ListWidget.create(container, list, {
|
||||
const widget_3 = ListWidget.create($container, list, {
|
||||
name: "replace-list",
|
||||
modifier: (item) => (rendering_item ? undefined : `${item}\n`),
|
||||
get_item,
|
||||
html_selector: (item) => `tr[data-item='${item}']`,
|
||||
simplebar_container: scroll_container,
|
||||
$simplebar_container: $scroll_container,
|
||||
});
|
||||
// Once we have initially rendered the widget, change the
|
||||
// behavior of the modifier function.
|
||||
@@ -834,16 +834,16 @@ run_test("render item", () => {
|
||||
});
|
||||
|
||||
run_test("Multiselect dropdown retain_selected_items", () => {
|
||||
const container = make_container();
|
||||
const scroll_container = make_scroll_container();
|
||||
const filter_element = make_filter_element();
|
||||
const $container = make_container();
|
||||
const $scroll_container = make_scroll_container();
|
||||
const $filter_element = make_filter_element();
|
||||
let data_rendered = [];
|
||||
|
||||
const list = ["one", "two", "three", "four"].map((x) => ({name: x, value: x}));
|
||||
const data = ["one"]; // Data initially selected.
|
||||
|
||||
container.html = () => {};
|
||||
container.find = (elem) => DropdownItem(elem);
|
||||
$container.html = () => {};
|
||||
$container.find = (elem) => DropdownItem(elem);
|
||||
|
||||
// We essentially create fake jQuery functions
|
||||
// whose return value are stored in objects so that
|
||||
@@ -880,8 +880,8 @@ run_test("Multiselect dropdown retain_selected_items", () => {
|
||||
return ListItem(element, temp);
|
||||
}
|
||||
|
||||
function prepend(data) {
|
||||
temp.prepended_data = data.html();
|
||||
function prepend($data) {
|
||||
temp.prepended_data = $data.html();
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -890,17 +890,17 @@ run_test("Multiselect dropdown retain_selected_items", () => {
|
||||
};
|
||||
}
|
||||
|
||||
const widget = ListWidget.create(container, list, {
|
||||
const widget = ListWidget.create($container, list, {
|
||||
name: "replace-list",
|
||||
modifier: (item) => `<li data-value="${item.value}">${item.name}</li>\n`,
|
||||
multiselect: {
|
||||
selected_items: data,
|
||||
},
|
||||
filter: {
|
||||
element: filter_element,
|
||||
$element: $filter_element,
|
||||
predicate: () => true,
|
||||
},
|
||||
simplebar_container: scroll_container,
|
||||
$simplebar_container: $scroll_container,
|
||||
});
|
||||
|
||||
const expected_value = [
|
||||
|
||||
@@ -268,18 +268,15 @@ test("marked_shared", () => {
|
||||
test("message_flags", () => {
|
||||
let message = {raw_content: "@**Leo**"};
|
||||
markdown.apply_markdown(message);
|
||||
assert.ok(!message.mentioned);
|
||||
assert.ok(!message.mentioned_me_directly);
|
||||
assert.ok(!message.flags.includes("mentioned"));
|
||||
|
||||
message = {raw_content: "@**Cordelia, Lear's daughter**"};
|
||||
markdown.apply_markdown(message);
|
||||
assert.ok(message.mentioned);
|
||||
assert.ok(message.mentioned_me_directly);
|
||||
assert.ok(message.flags.includes("mentioned"));
|
||||
|
||||
message = {raw_content: "@**all**"};
|
||||
markdown.apply_markdown(message);
|
||||
assert.ok(message.mentioned);
|
||||
assert.ok(!message.mentioned_me_directly);
|
||||
assert.ok(message.flags.includes("wildcard_mentioned"));
|
||||
});
|
||||
|
||||
test("marked", () => {
|
||||
@@ -680,77 +677,87 @@ test("message_flags", () => {
|
||||
markdown.apply_markdown(message);
|
||||
|
||||
assert.equal(message.is_me_message, false);
|
||||
assert.equal(message.mentioned, true);
|
||||
assert.equal(message.mentioned_me_directly, true);
|
||||
|
||||
assert.equal(message.flags.includes("mentioned"), true);
|
||||
assert.equal(message.flags.includes("wildcard_mentioned"), true);
|
||||
input = "test @**everyone**";
|
||||
message = {topic: "No links here", raw_content: input};
|
||||
markdown.apply_markdown(message);
|
||||
assert.equal(message.is_me_message, false);
|
||||
assert.equal(message.mentioned, true);
|
||||
assert.equal(message.mentioned_me_directly, false);
|
||||
assert.equal(message.flags.includes("wildcard_mentioned"), true);
|
||||
assert.equal(message.flags.includes("mentioned"), false);
|
||||
|
||||
input = "test @**stream**";
|
||||
message = {topic: "No links here", raw_content: input};
|
||||
markdown.apply_markdown(message);
|
||||
assert.equal(message.is_me_message, false);
|
||||
assert.equal(message.mentioned, true);
|
||||
assert.equal(message.mentioned_me_directly, false);
|
||||
assert.equal(message.flags.includes("wildcard_mentioned"), true);
|
||||
assert.equal(message.flags.includes("mentioned"), false);
|
||||
|
||||
input = "test @all";
|
||||
message = {topic: "No links here", raw_content: input};
|
||||
markdown.apply_markdown(message);
|
||||
assert.equal(message.mentioned, false);
|
||||
assert.equal(message.flags.includes("wildcard_mentioned"), false);
|
||||
assert.equal(message.flags.includes("mentioned"), false);
|
||||
|
||||
input = "test @everyone";
|
||||
message = {topic: "No links here", raw_content: input};
|
||||
markdown.apply_markdown(message);
|
||||
assert.equal(message.mentioned, false);
|
||||
assert.equal(message.flags.includes("wildcard_mentioned"), false);
|
||||
assert.equal(message.flags.includes("mentioned"), false);
|
||||
|
||||
input = "test @any";
|
||||
message = {topic: "No links here", raw_content: input};
|
||||
markdown.apply_markdown(message);
|
||||
assert.equal(message.mentioned, false);
|
||||
assert.equal(message.flags.includes("wildcard_mentioned"), false);
|
||||
assert.equal(message.flags.includes("mentioned"), false);
|
||||
|
||||
input = "test @alleycat.com";
|
||||
message = {topic: "No links here", raw_content: input};
|
||||
markdown.apply_markdown(message);
|
||||
assert.equal(message.mentioned, false);
|
||||
assert.equal(message.flags.includes("wildcard_mentioned"), false);
|
||||
assert.equal(message.flags.includes("mentioned"), false);
|
||||
|
||||
input = "test @*hamletcharacters*";
|
||||
message = {topic: "No links here", raw_content: input};
|
||||
markdown.apply_markdown(message);
|
||||
assert.equal(message.mentioned, true);
|
||||
assert.equal(message.flags.includes("wildcard_mentioned"), false);
|
||||
assert.equal(message.flags.includes("mentioned"), true);
|
||||
|
||||
input = "test @*backend*";
|
||||
message = {topic: "No links here", raw_content: input};
|
||||
markdown.apply_markdown(message);
|
||||
assert.equal(message.mentioned, false);
|
||||
assert.equal(message.flags.includes("wildcard_mentioned"), false);
|
||||
assert.equal(message.flags.includes("mentioned"), false);
|
||||
|
||||
input = "test @**invalid_user**";
|
||||
message = {topic: "No links here", raw_content: input};
|
||||
markdown.apply_markdown(message);
|
||||
assert.equal(message.mentioned, false);
|
||||
assert.equal(message.flags.includes("wildcard_mentioned"), false);
|
||||
assert.equal(message.flags.includes("mentioned"), false);
|
||||
|
||||
input = "test @_**all**";
|
||||
message = {topic: "No links here", raw_content: input};
|
||||
markdown.apply_markdown(message);
|
||||
assert.equal(message.mentioned, false);
|
||||
assert.equal(message.flags.includes("wildcard_mentioned"), false);
|
||||
assert.equal(message.flags.includes("mentioned"), false);
|
||||
|
||||
input = "> test @**all**";
|
||||
message = {topic: "No links here", raw_content: input};
|
||||
markdown.apply_markdown(message);
|
||||
assert.equal(message.mentioned, false);
|
||||
assert.equal(message.flags.includes("wildcard_mentioned"), false);
|
||||
assert.equal(message.flags.includes("mentioned"), false);
|
||||
|
||||
input = "test @_*hamletcharacters*";
|
||||
message = {topic: "No links here", raw_content: input};
|
||||
markdown.apply_markdown(message);
|
||||
assert.equal(message.mentioned, false);
|
||||
assert.equal(message.flags.includes("wildcard_mentioned"), false);
|
||||
assert.equal(message.flags.includes("mentioned"), false);
|
||||
|
||||
input = "> test @*hamletcharacters*";
|
||||
message = {topic: "No links here", raw_content: input};
|
||||
markdown.apply_markdown(message);
|
||||
assert.equal(message.mentioned, false);
|
||||
assert.equal(message.flags.includes("wildcard_mentioned"), false);
|
||||
assert.equal(message.flags.includes("mentioned"), false);
|
||||
});
|
||||
|
||||
test("backend_only_linkifiers", () => {
|
||||
|
||||
149
frontend_tests/node_tests/markdown_parse.js
Normal file
149
frontend_tests/node_tests/markdown_parse.js
Normal file
@@ -0,0 +1,149 @@
|
||||
"use strict";
|
||||
|
||||
const {strict: assert} = require("assert");
|
||||
|
||||
const {zrequire} = require("../zjsunit/namespace");
|
||||
const {run_test} = require("../zjsunit/test");
|
||||
|
||||
const markdown = zrequire("markdown");
|
||||
|
||||
const my_id = 101;
|
||||
|
||||
const user_map = new Map();
|
||||
user_map.set(my_id, "Me Myself");
|
||||
user_map.set(105, "greg");
|
||||
|
||||
function get_actual_name_from_user_id(user_id) {
|
||||
return user_map.get(user_id);
|
||||
}
|
||||
|
||||
function get_user_id_from_name(name) {
|
||||
for (const [user_id, _name] of user_map.entries()) {
|
||||
if (name === _name) {
|
||||
return user_id;
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function is_valid_full_name_and_user_id(name, user_id) {
|
||||
return user_map.has(user_id) && user_map.get(user_id) === name;
|
||||
}
|
||||
|
||||
function my_user_id() {
|
||||
return my_id;
|
||||
}
|
||||
|
||||
function is_valid_user_id(user_id) {
|
||||
return user_map.has(user_id);
|
||||
}
|
||||
|
||||
const staff_group = {
|
||||
id: 201,
|
||||
name: "Staff",
|
||||
};
|
||||
|
||||
const user_group_map = new Map();
|
||||
user_group_map.set(staff_group.name, staff_group);
|
||||
|
||||
function get_user_group_from_name(name) {
|
||||
return user_group_map.get(name);
|
||||
}
|
||||
|
||||
function is_member_of_user_group(user_group_id, user_id) {
|
||||
assert.equal(user_group_id, staff_group.id);
|
||||
assert.equal(user_id, my_id);
|
||||
return true;
|
||||
}
|
||||
|
||||
const social = {
|
||||
stream_id: 301,
|
||||
name: "social",
|
||||
};
|
||||
|
||||
const sub_map = new Map();
|
||||
sub_map.set(social.name, social);
|
||||
|
||||
function get_stream_by_name(name) {
|
||||
return sub_map.get(name);
|
||||
}
|
||||
|
||||
function stream_hash(stream_id) {
|
||||
return `stream-${stream_id}`;
|
||||
}
|
||||
|
||||
function stream_topic_hash(stream_id, topic) {
|
||||
return `stream-${stream_id}-topic-${topic}`;
|
||||
}
|
||||
|
||||
const helper_config = {
|
||||
// user stuff
|
||||
get_actual_name_from_user_id,
|
||||
get_user_id_from_name,
|
||||
is_valid_full_name_and_user_id,
|
||||
is_valid_user_id,
|
||||
my_user_id,
|
||||
|
||||
// user groups
|
||||
get_user_group_from_name,
|
||||
is_member_of_user_group,
|
||||
|
||||
// stream hashes
|
||||
get_stream_by_name,
|
||||
stream_hash,
|
||||
stream_topic_hash,
|
||||
|
||||
// settings
|
||||
should_translate_emoticons: () => false,
|
||||
};
|
||||
|
||||
function assert_parse(raw_content, expected_content) {
|
||||
const {content} = markdown.parse({raw_content, helper_config});
|
||||
assert.equal(content, expected_content);
|
||||
}
|
||||
|
||||
function test(label, f) {
|
||||
markdown.setup();
|
||||
run_test(label, f);
|
||||
}
|
||||
|
||||
test("basics", () => {
|
||||
assert_parse("boring", "<p>boring</p>");
|
||||
assert_parse("**bold**", "<p><strong>bold</strong></p>");
|
||||
});
|
||||
|
||||
test("user mentions", () => {
|
||||
assert_parse("@**greg**", '<p><span class="user-mention" data-user-id="105">@greg</span></p>');
|
||||
|
||||
assert_parse("@**|105**", '<p><span class="user-mention" data-user-id="105">@greg</span></p>');
|
||||
|
||||
assert_parse(
|
||||
"@**greg|105**",
|
||||
'<p><span class="user-mention" data-user-id="105">@greg</span></p>',
|
||||
);
|
||||
|
||||
assert_parse(
|
||||
"@**Me Myself|101**",
|
||||
'<p><span class="user-mention" data-user-id="101">@Me Myself</span></p>',
|
||||
);
|
||||
});
|
||||
|
||||
test("user group mentions", () => {
|
||||
assert_parse(
|
||||
"@*Staff*",
|
||||
'<p><span class="user-group-mention" data-user-group-id="201">@Staff</span></p>',
|
||||
);
|
||||
});
|
||||
|
||||
test("stream links", () => {
|
||||
assert_parse(
|
||||
"#**social**",
|
||||
'<p><a class="stream" data-stream-id="301" href="/stream-301">#social</a></p>',
|
||||
);
|
||||
|
||||
assert_parse(
|
||||
"#**social>lunch**",
|
||||
'<p><a class="stream-topic" data-stream-id="301" href="/stream-301-topic-lunch">#social > lunch</a></p>',
|
||||
);
|
||||
});
|
||||
@@ -158,3 +158,114 @@ run_test("get_deletability", ({override}) => {
|
||||
message.timestamp = current_timestamp - 60;
|
||||
assert.equal(message_edit.get_deletability(message), false);
|
||||
});
|
||||
|
||||
run_test("stream_and_topic_exist_in_edit_history", () => {
|
||||
// A message with no edit history should always return false;
|
||||
// the message's current stream_id and topic are not compared
|
||||
// to the stream_id and topic parameters.
|
||||
const message_no_edits = {
|
||||
stream_id: 1,
|
||||
topic: "topic match",
|
||||
};
|
||||
assert.equal(
|
||||
message_edit.stream_and_topic_exist_in_edit_history(message_no_edits, 2, "no match"),
|
||||
false,
|
||||
);
|
||||
assert.equal(
|
||||
message_edit.stream_and_topic_exist_in_edit_history(message_no_edits, 1, "topic match"),
|
||||
false,
|
||||
);
|
||||
|
||||
// A non-stream message (object has no stream_id or topic)
|
||||
// with content edit history, should return false.
|
||||
const private_message = {
|
||||
edit_history: [{prev_content: "content edit to PM"}],
|
||||
};
|
||||
assert.equal(
|
||||
message_edit.stream_and_topic_exist_in_edit_history(private_message, 1, "topic match"),
|
||||
false,
|
||||
);
|
||||
|
||||
// A stream message with only content edits should return false,
|
||||
// even if the message's current stream_id and topic are a match.
|
||||
const message_content_edit = {
|
||||
stream_id: 1,
|
||||
topic: "topic match",
|
||||
edit_history: [{prev_content: "content edit"}],
|
||||
};
|
||||
assert.equal(
|
||||
message_edit.stream_and_topic_exist_in_edit_history(message_content_edit, 1, "topic match"),
|
||||
false,
|
||||
);
|
||||
|
||||
const message_stream_edit = {
|
||||
stream_id: 6,
|
||||
topic: "topic match",
|
||||
edit_history: [{stream: 6, prev_stream: 1}],
|
||||
};
|
||||
assert.equal(
|
||||
message_edit.stream_and_topic_exist_in_edit_history(message_stream_edit, 2, "topic match"),
|
||||
false,
|
||||
);
|
||||
assert.equal(
|
||||
message_edit.stream_and_topic_exist_in_edit_history(message_stream_edit, 1, "topic match"),
|
||||
true,
|
||||
);
|
||||
|
||||
const message_topic_edit = {
|
||||
stream_id: 1,
|
||||
topic: "final topic",
|
||||
edit_history: [{topic: "final topic", prev_topic: "topic match"}],
|
||||
};
|
||||
assert.equal(
|
||||
message_edit.stream_and_topic_exist_in_edit_history(message_topic_edit, 1, "no match"),
|
||||
false,
|
||||
);
|
||||
assert.equal(
|
||||
message_edit.stream_and_topic_exist_in_edit_history(message_topic_edit, 1, "topic match"),
|
||||
true,
|
||||
);
|
||||
|
||||
const message_many_edits = {
|
||||
stream_id: 6,
|
||||
topic: "final topic",
|
||||
edit_history: [
|
||||
{stream: 6, prev_stream: 5},
|
||||
{prev_content: "content only edit"},
|
||||
{topic: "final topic", prev_topic: "topic match"},
|
||||
{stream: 5, prev_stream: 1},
|
||||
],
|
||||
};
|
||||
assert.equal(
|
||||
message_edit.stream_and_topic_exist_in_edit_history(message_many_edits, 1, "no match"),
|
||||
false,
|
||||
);
|
||||
assert.equal(
|
||||
message_edit.stream_and_topic_exist_in_edit_history(message_many_edits, 2, "topic match"),
|
||||
false,
|
||||
);
|
||||
assert.equal(
|
||||
message_edit.stream_and_topic_exist_in_edit_history(message_many_edits, 1, "topic match"),
|
||||
true,
|
||||
);
|
||||
|
||||
// When the topic and stream_id exist in the message's edit history
|
||||
// individually, but not together in a historical state, it should return false.
|
||||
const message_no_historical_match = {
|
||||
stream_id: 6,
|
||||
topic: "final topic",
|
||||
edit_history: [
|
||||
{stream: 6, prev_stream: 1}, // stream matches, topic does not
|
||||
{stream: 1, prev_stream: 5}, // neither match
|
||||
{topic: "final topic", prev_topic: "topic match"}, // topic matches, stream does not
|
||||
],
|
||||
};
|
||||
assert.equal(
|
||||
message_edit.stream_and_topic_exist_in_edit_history(
|
||||
message_no_historical_match,
|
||||
1,
|
||||
"topic match",
|
||||
),
|
||||
false,
|
||||
);
|
||||
});
|
||||
|
||||
@@ -20,7 +20,6 @@ message_lists.current = {};
|
||||
const people = zrequire("people");
|
||||
const message_events = zrequire("message_events");
|
||||
const message_helper = zrequire("message_helper");
|
||||
const message_store = zrequire("message_store");
|
||||
const stream_data = zrequire("stream_data");
|
||||
const stream_topic_history = zrequire("stream_topic_history");
|
||||
const unread = zrequire("unread");
|
||||
@@ -70,7 +69,6 @@ run_test("update_messages", () => {
|
||||
};
|
||||
|
||||
message_helper.process_new_message(original_message);
|
||||
message_store.set_message_booleans(original_message);
|
||||
|
||||
assert.equal(original_message.mentioned, true);
|
||||
assert.equal(original_message.unread, true);
|
||||
@@ -117,9 +115,9 @@ run_test("update_messages", () => {
|
||||
page_params.realm_allow_edit_history = false;
|
||||
message_list.narrowed = "stub-to-ignore";
|
||||
|
||||
const message_edit_history_modal = $.create("#message-edit-history");
|
||||
const modal = $.create("micromodal").addClass("modal--open");
|
||||
message_edit_history_modal.set_parents_result(".micromodal", modal);
|
||||
const $message_edit_history_modal = $.create("#message-edit-history");
|
||||
const $modal = $.create("micromodal").addClass("modal--open");
|
||||
$message_edit_history_modal.set_parents_result(".micromodal", $modal);
|
||||
|
||||
// TEST THIS:
|
||||
message_events.update_messages(events);
|
||||
|
||||
@@ -31,7 +31,6 @@ mock_esm("../../static/js/ui_report", {
|
||||
const channel = mock_esm("../../static/js/channel");
|
||||
const message_helper = mock_esm("../../static/js/message_helper");
|
||||
const message_lists = mock_esm("../../static/js/message_lists");
|
||||
const message_store = mock_esm("../../static/js/message_store");
|
||||
const message_util = mock_esm("../../static/js/message_util");
|
||||
const pm_list = mock_esm("../../static/js/pm_list");
|
||||
const stream_list = mock_esm("../../static/js/stream_list", {
|
||||
@@ -119,14 +118,13 @@ function config_fake_channel(conf) {
|
||||
function config_process_results(messages) {
|
||||
const self = {};
|
||||
|
||||
const messages_processed_for_bools = [];
|
||||
const messages_processed_for_new = [];
|
||||
|
||||
message_store.set_message_booleans = (message) => {
|
||||
messages_processed_for_bools.push(message);
|
||||
message_helper.process_new_message = (message) => {
|
||||
messages_processed_for_new.push(message);
|
||||
return message;
|
||||
};
|
||||
|
||||
message_helper.process_new_message = (message) => message;
|
||||
|
||||
message_util.do_unread_count_updates = (arg) => {
|
||||
assert.deepEqual(arg, messages);
|
||||
};
|
||||
@@ -141,7 +139,7 @@ function config_process_results(messages) {
|
||||
pm_list.update_private_messages = noop;
|
||||
|
||||
self.verify = () => {
|
||||
assert.deepEqual(messages_processed_for_bools, messages);
|
||||
assert.deepEqual(messages_processed_for_new, messages);
|
||||
};
|
||||
|
||||
return self;
|
||||
|
||||
@@ -110,7 +110,6 @@ test("process_new_message", () => {
|
||||
is_me_message: false,
|
||||
id: 2067,
|
||||
};
|
||||
message_store.set_message_booleans(message);
|
||||
message_helper.process_new_message(message);
|
||||
|
||||
assert.deepEqual(message_user_ids.user_ids().sort(), [me.user_id, bob.user_id, cindy.user_id]);
|
||||
@@ -153,7 +152,6 @@ test("process_new_message", () => {
|
||||
id: 2068,
|
||||
};
|
||||
|
||||
message_store.set_message_booleans(message);
|
||||
message_helper.process_new_message(message);
|
||||
assert.deepEqual(message.stream, message.display_recipient);
|
||||
assert.equal(message.reply_to, "denise@example.com");
|
||||
@@ -307,7 +305,6 @@ test("update_property", () => {
|
||||
id: 101,
|
||||
};
|
||||
for (const message of [message1, message2]) {
|
||||
message_store.set_message_booleans(message);
|
||||
message_helper.process_new_message(message);
|
||||
}
|
||||
|
||||
|
||||
@@ -449,7 +449,6 @@ run_test("show_empty_narrow_message_with_search", ({mock_template}) => {
|
||||
});
|
||||
|
||||
run_test("hide_empty_narrow_message", () => {
|
||||
$(".empty_feed_notice_main").html("<div class='empty_feed_notice'>Nothing here</div>");
|
||||
narrow_banner.hide_empty_narrow_message();
|
||||
assert.equal($(".empty_feed_notice").text(), "never-been-set");
|
||||
});
|
||||
|
||||
@@ -27,47 +27,47 @@ run_test("basics w/progress bar", () => {
|
||||
let password;
|
||||
let warning;
|
||||
|
||||
const bar = (function () {
|
||||
const self = {};
|
||||
const $bar = (function () {
|
||||
const $self = {};
|
||||
|
||||
self.width = (width) => {
|
||||
self.w = width;
|
||||
return self;
|
||||
$self.width = (width) => {
|
||||
$self.w = width;
|
||||
return $self;
|
||||
};
|
||||
|
||||
self.removeClass = (arg) => {
|
||||
$self.removeClass = (arg) => {
|
||||
assert.equal(arg, "bar-success bar-danger");
|
||||
return self;
|
||||
return $self;
|
||||
};
|
||||
|
||||
self.addClass = (arg) => {
|
||||
self.added_class = arg;
|
||||
return self;
|
||||
$self.addClass = (arg) => {
|
||||
$self.added_class = arg;
|
||||
return $self;
|
||||
};
|
||||
|
||||
return self;
|
||||
return $self;
|
||||
})();
|
||||
|
||||
password = "z!X4@S_&";
|
||||
accepted = password_quality(password, bar, password_field(10, 80000));
|
||||
accepted = password_quality(password, $bar, password_field(10, 80000));
|
||||
assert.ok(!accepted);
|
||||
assert.equal(bar.w, "39.7%");
|
||||
assert.equal(bar.added_class, "bar-danger");
|
||||
assert.equal($bar.w, "39.7%");
|
||||
assert.equal($bar.added_class, "bar-danger");
|
||||
warning = password_warning(password, password_field(10));
|
||||
assert.equal(warning, "translated: Password should be at least 10 characters long");
|
||||
|
||||
password = "foo";
|
||||
accepted = password_quality(password, bar, password_field(2, 200));
|
||||
accepted = password_quality(password, $bar, password_field(2, 200));
|
||||
assert.ok(accepted);
|
||||
assert.equal(bar.w, "10.390277164940581%");
|
||||
assert.equal(bar.added_class, "bar-success");
|
||||
assert.equal($bar.w, "10.390277164940581%");
|
||||
assert.equal($bar.added_class, "bar-success");
|
||||
warning = password_warning(password, password_field(2));
|
||||
assert.equal(warning, "translated: Password is too weak");
|
||||
|
||||
password = "aaaaaaaa";
|
||||
accepted = password_quality(password, bar, password_field(6, 1e100));
|
||||
accepted = password_quality(password, $bar, password_field(6, 1e100));
|
||||
assert.ok(!accepted);
|
||||
assert.equal(bar.added_class, "bar-danger");
|
||||
assert.equal($bar.added_class, "bar-danger");
|
||||
warning = password_warning(password, password_field(6));
|
||||
assert.equal(warning, 'Repeats like "aaa" are easy to guess');
|
||||
assert.equal(warning, 'Repeated characters like "aaa" are easy to guess.');
|
||||
});
|
||||
|
||||
@@ -19,19 +19,19 @@ const user_groups = zrequire("user_groups");
|
||||
// set global test variables.
|
||||
let sort_recipients_called = false;
|
||||
let sort_streams_called = false;
|
||||
const fake_rendered_person = $.create("fake-rendered-person");
|
||||
const fake_rendered_stream = $.create("fake-rendered-stream");
|
||||
const fake_rendered_group = $.create("fake-rendered-group");
|
||||
const $fake_rendered_person = $.create("fake-rendered-person");
|
||||
const $fake_rendered_stream = $.create("fake-rendered-stream");
|
||||
const $fake_rendered_group = $.create("fake-rendered-group");
|
||||
|
||||
mock_esm("../../static/js/typeahead_helper", {
|
||||
render_person() {
|
||||
return fake_rendered_person;
|
||||
return $fake_rendered_person;
|
||||
},
|
||||
render_user_group() {
|
||||
return fake_rendered_group;
|
||||
return $fake_rendered_group;
|
||||
},
|
||||
render_stream() {
|
||||
return fake_rendered_stream;
|
||||
return $fake_rendered_stream;
|
||||
},
|
||||
sort_streams() {
|
||||
sort_streams_called = true;
|
||||
@@ -113,20 +113,20 @@ run_test("set_up", ({mock_template}) => {
|
||||
return html;
|
||||
});
|
||||
let input_pill_typeahead_called = false;
|
||||
const fake_input = $.create(".input");
|
||||
fake_input.before = noop;
|
||||
const $fake_input = $.create(".input");
|
||||
$fake_input.before = noop;
|
||||
|
||||
const container = $.create(".pill-container");
|
||||
container.find = () => fake_input;
|
||||
const $container = $.create(".pill-container");
|
||||
$container.find = () => $fake_input;
|
||||
|
||||
const pill_widget = input_pill.create({
|
||||
container,
|
||||
const $pill_widget = input_pill.create({
|
||||
$container,
|
||||
create_item_from_text: noop,
|
||||
get_text_from_item: noop,
|
||||
});
|
||||
|
||||
let opts = {};
|
||||
fake_input.typeahead = (config) => {
|
||||
$fake_input.typeahead = (config) => {
|
||||
assert.equal(config.items, 5);
|
||||
assert.ok(config.fixed);
|
||||
assert.ok(config.dropup);
|
||||
@@ -154,7 +154,7 @@ run_test("set_up", ({mock_template}) => {
|
||||
// Test stream highlighter for widgets that allow stream pills.
|
||||
assert.equal(
|
||||
config.highlighter.call(fake_stream_this, denmark),
|
||||
fake_rendered_stream,
|
||||
$fake_rendered_stream,
|
||||
);
|
||||
}
|
||||
if (opts.user_group && opts.user) {
|
||||
@@ -162,17 +162,17 @@ run_test("set_up", ({mock_template}) => {
|
||||
// then we should check that each of them rendered correctly.
|
||||
assert.equal(
|
||||
config.highlighter.call(fake_group_this, testers),
|
||||
fake_rendered_group,
|
||||
$fake_rendered_group,
|
||||
);
|
||||
assert.equal(config.highlighter.call(fake_person_this, me), fake_rendered_person);
|
||||
assert.equal(config.highlighter.call(fake_person_this, me), $fake_rendered_person);
|
||||
}
|
||||
if (opts.user && !opts.user_group) {
|
||||
assert.equal(config.highlighter.call(fake_person_this, me), fake_rendered_person);
|
||||
assert.equal(config.highlighter.call(fake_person_this, me), $fake_rendered_person);
|
||||
}
|
||||
if (!opts.user && opts.user_group) {
|
||||
assert.equal(
|
||||
config.highlighter.call(fake_group_this, testers),
|
||||
fake_rendered_group,
|
||||
$fake_rendered_group,
|
||||
);
|
||||
}
|
||||
})();
|
||||
@@ -288,7 +288,7 @@ run_test("set_up", ({mock_template}) => {
|
||||
// updater in pill_typeahead.
|
||||
|
||||
function number_of_pills() {
|
||||
const pills = pill_widget.items();
|
||||
const pills = $pill_widget.items();
|
||||
return pills.length;
|
||||
}
|
||||
assert.equal(number_of_pills(), 0);
|
||||
@@ -307,7 +307,7 @@ run_test("set_up", ({mock_template}) => {
|
||||
};
|
||||
|
||||
function test_pill_typeahead(opts) {
|
||||
pill_typeahead.set_up(fake_input, pill_widget, opts);
|
||||
pill_typeahead.set_up($fake_input, $pill_widget, opts);
|
||||
assert.ok(input_pill_typeahead_called);
|
||||
}
|
||||
|
||||
@@ -339,6 +339,6 @@ run_test("set_up", ({mock_template}) => {
|
||||
opts = {};
|
||||
input_pill_typeahead_called = false;
|
||||
blueslip.expect("error", "Unspecified possible item types");
|
||||
pill_typeahead.set_up(fake_input, pill_widget, {});
|
||||
pill_typeahead.set_up($fake_input, $pill_widget, {});
|
||||
assert.ok(!input_pill_typeahead_called);
|
||||
});
|
||||
|
||||
@@ -2,36 +2,37 @@
|
||||
|
||||
const {strict: assert} = require("assert");
|
||||
|
||||
const {mock_esm, zrequire} = require("../zjsunit/namespace");
|
||||
const {zrequire} = require("../zjsunit/namespace");
|
||||
const {run_test} = require("../zjsunit/test");
|
||||
const $ = require("../zjsunit/zjquery");
|
||||
|
||||
const narrow_state = mock_esm("../../static/js/narrow_state");
|
||||
|
||||
const narrow_state = zrequire("narrow_state");
|
||||
const pm_list = zrequire("pm_list");
|
||||
|
||||
run_test("update_dom_with_unread_counts", ({override}) => {
|
||||
run_test("update_dom_with_unread_counts", () => {
|
||||
let counts;
|
||||
|
||||
override(narrow_state, "active", () => true);
|
||||
// simulate an active narrow
|
||||
narrow_state.set_current_filter("stub");
|
||||
assert.equal(narrow_state.active(), true);
|
||||
|
||||
const total_count = $.create("total-count-stub");
|
||||
const private_li = $(".top_left_private_messages .private_messages_header");
|
||||
private_li.set_find_results(".unread_count", total_count);
|
||||
const $total_count = $.create("total-count-stub");
|
||||
const $private_li = $(".top_left_private_messages .private_messages_header");
|
||||
$private_li.set_find_results(".unread_count", $total_count);
|
||||
|
||||
counts = {
|
||||
private_message_count: 10,
|
||||
};
|
||||
|
||||
pm_list.update_dom_with_unread_counts(counts);
|
||||
assert.equal(total_count.text(), "10");
|
||||
assert.ok(total_count.visible());
|
||||
assert.equal($total_count.text(), "10");
|
||||
assert.ok($total_count.visible());
|
||||
|
||||
counts = {
|
||||
private_message_count: 0,
|
||||
};
|
||||
|
||||
pm_list.update_dom_with_unread_counts(counts);
|
||||
assert.equal(total_count.text(), "");
|
||||
assert.ok(!total_count.visible());
|
||||
assert.equal($total_count.text(), "");
|
||||
assert.ok(!$total_count.visible());
|
||||
});
|
||||
|
||||
@@ -5,7 +5,6 @@ const {strict: assert} = require("assert");
|
||||
const {mock_esm, zrequire} = require("../zjsunit/namespace");
|
||||
const {run_test} = require("../zjsunit/test");
|
||||
|
||||
const narrow_state = mock_esm("../../static/js/narrow_state");
|
||||
const unread = mock_esm("../../static/js/unread");
|
||||
|
||||
mock_esm("../../static/js/user_status", {
|
||||
@@ -15,6 +14,7 @@ mock_esm("../../static/js/user_status", {
|
||||
}),
|
||||
});
|
||||
|
||||
const narrow_state = zrequire("narrow_state");
|
||||
const people = zrequire("people");
|
||||
const pm_conversations = zrequire("pm_conversations");
|
||||
const pm_list_data = zrequire("pm_list_data");
|
||||
@@ -49,6 +49,7 @@ people.initialize_current_user(me.user_id);
|
||||
|
||||
function test(label, f) {
|
||||
run_test(label, ({override, override_rewire}) => {
|
||||
narrow_state.reset_current_filter();
|
||||
pm_conversations.clear_for_testing();
|
||||
f({override, override_rewire});
|
||||
});
|
||||
@@ -60,7 +61,7 @@ test("get_convos", ({override}) => {
|
||||
let num_unread_for_person = 1;
|
||||
override(unread, "num_unread_for_person", () => num_unread_for_person);
|
||||
|
||||
override(narrow_state, "filter", () => {});
|
||||
assert.equal(narrow_state.filter(), undefined);
|
||||
|
||||
const expected_data = [
|
||||
{
|
||||
@@ -111,7 +112,7 @@ test("get_convos bot", ({override}) => {
|
||||
|
||||
override(unread, "num_unread_for_person", () => 1);
|
||||
|
||||
override(narrow_state, "filter", () => {});
|
||||
assert.equal(narrow_state.filter(), undefined);
|
||||
|
||||
const expected_data = [
|
||||
{
|
||||
@@ -142,20 +143,17 @@ test("get_convos bot", ({override}) => {
|
||||
assert.deepEqual(pm_data, expected_data);
|
||||
});
|
||||
|
||||
test("get_active_user_ids_string", ({override}) => {
|
||||
let active_filter;
|
||||
|
||||
override(narrow_state, "filter", () => active_filter);
|
||||
|
||||
test("get_active_user_ids_string", () => {
|
||||
assert.equal(pm_list_data.get_active_user_ids_string(), undefined);
|
||||
|
||||
function set_filter_result(emails) {
|
||||
active_filter = {
|
||||
const active_filter = {
|
||||
operands: (operand) => {
|
||||
assert.equal(operand, "pm-with");
|
||||
return emails;
|
||||
},
|
||||
};
|
||||
narrow_state.set_current_filter(active_filter);
|
||||
}
|
||||
|
||||
set_filter_result([]);
|
||||
@@ -174,13 +172,10 @@ function private_filter() {
|
||||
};
|
||||
}
|
||||
|
||||
test("is_all_privates", ({override}) => {
|
||||
let filter;
|
||||
override(narrow_state, "filter", () => filter);
|
||||
|
||||
filter = undefined;
|
||||
test("is_all_privates", () => {
|
||||
assert.equal(narrow_state.filter(), undefined);
|
||||
assert.equal(pm_list_data.is_all_privates(), false);
|
||||
|
||||
filter = private_filter();
|
||||
narrow_state.set_current_filter(private_filter());
|
||||
assert.equal(pm_list_data.is_all_privates(), true);
|
||||
});
|
||||
|
||||
@@ -210,7 +210,7 @@ run_test("activate another person poll", ({mock_template}) => {
|
||||
mock_template("widgets/poll_widget.hbs", false, () => "widgets/poll_widget");
|
||||
mock_template("widgets/poll_widget_results.hbs", false, () => "widgets/poll_widget_results");
|
||||
|
||||
const widget_elem = $("<div>").addClass("widget-content");
|
||||
const $widget_elem = $("<div>").addClass("widget-content");
|
||||
|
||||
let out_data; // Used to check the event data sent to the server
|
||||
const callback = (data) => {
|
||||
@@ -218,7 +218,7 @@ run_test("activate another person poll", ({mock_template}) => {
|
||||
};
|
||||
|
||||
const opts = {
|
||||
elem: widget_elem,
|
||||
$elem: $widget_elem,
|
||||
callback,
|
||||
message: {
|
||||
sender_id: alice.user_id,
|
||||
@@ -229,53 +229,53 @@ run_test("activate another person poll", ({mock_template}) => {
|
||||
};
|
||||
|
||||
const set_widget_find_result = (selector) => {
|
||||
const elem = $.create(selector);
|
||||
widget_elem.set_find_results(selector, elem);
|
||||
return elem;
|
||||
const $elem = $.create(selector);
|
||||
$widget_elem.set_find_results(selector, $elem);
|
||||
return $elem;
|
||||
};
|
||||
|
||||
const poll_option = set_widget_find_result("button.poll-option");
|
||||
const poll_option_input = set_widget_find_result("input.poll-option");
|
||||
const widget_option_container = set_widget_find_result("ul.poll-widget");
|
||||
const $poll_option = set_widget_find_result("button.poll-option");
|
||||
const $poll_option_input = set_widget_find_result("input.poll-option");
|
||||
const $widget_option_container = set_widget_find_result("ul.poll-widget");
|
||||
|
||||
const poll_question_submit = set_widget_find_result("button.poll-question-check");
|
||||
const poll_edit_question = set_widget_find_result(".poll-edit-question");
|
||||
const poll_question_header = set_widget_find_result(".poll-question-header");
|
||||
const poll_question_container = set_widget_find_result(".poll-question-bar");
|
||||
const poll_option_container = set_widget_find_result(".poll-option-bar");
|
||||
const $poll_question_submit = set_widget_find_result("button.poll-question-check");
|
||||
const $poll_edit_question = set_widget_find_result(".poll-edit-question");
|
||||
const $poll_question_header = set_widget_find_result(".poll-question-header");
|
||||
const $poll_question_container = set_widget_find_result(".poll-question-bar");
|
||||
const $poll_option_container = set_widget_find_result(".poll-option-bar");
|
||||
|
||||
const poll_vote_button = set_widget_find_result("button.poll-vote");
|
||||
const poll_please_wait = set_widget_find_result(".poll-please-wait");
|
||||
const poll_author_help = set_widget_find_result(".poll-author-help");
|
||||
const $poll_vote_button = set_widget_find_result("button.poll-vote");
|
||||
const $poll_please_wait = set_widget_find_result(".poll-please-wait");
|
||||
const $poll_author_help = set_widget_find_result(".poll-author-help");
|
||||
|
||||
set_widget_find_result("button.poll-question-remove");
|
||||
set_widget_find_result("input.poll-question");
|
||||
|
||||
poll_widget.activate(opts);
|
||||
|
||||
assert.ok(poll_option_container.visible());
|
||||
assert.ok(poll_question_header.visible());
|
||||
assert.ok($poll_option_container.visible());
|
||||
assert.ok($poll_question_header.visible());
|
||||
|
||||
assert.ok(!poll_question_container.visible());
|
||||
assert.ok(!poll_question_submit.visible());
|
||||
assert.ok(!poll_edit_question.visible());
|
||||
assert.ok(!poll_please_wait.visible());
|
||||
assert.ok(!poll_author_help.visible());
|
||||
assert.ok(!$poll_question_container.visible());
|
||||
assert.ok(!$poll_question_submit.visible());
|
||||
assert.ok(!$poll_edit_question.visible());
|
||||
assert.ok(!$poll_please_wait.visible());
|
||||
assert.ok(!$poll_author_help.visible());
|
||||
|
||||
assert.equal(widget_elem.html(), "widgets/poll_widget");
|
||||
assert.equal(widget_option_container.html(), "widgets/poll_widget_results");
|
||||
assert.equal(poll_question_header.text(), "What do you want?");
|
||||
assert.equal($widget_elem.html(), "widgets/poll_widget");
|
||||
assert.equal($widget_option_container.html(), "widgets/poll_widget_results");
|
||||
assert.equal($poll_question_header.text(), "What do you want?");
|
||||
|
||||
{
|
||||
/* Testing data sent to server on adding option */
|
||||
poll_option_input.val("cool choice");
|
||||
$poll_option_input.val("cool choice");
|
||||
out_data = undefined;
|
||||
poll_option.trigger("click");
|
||||
$poll_option.trigger("click");
|
||||
assert.deepEqual(out_data, {type: "new_option", idx: 1, option: "cool choice"});
|
||||
|
||||
poll_option_input.val("");
|
||||
$poll_option_input.val("");
|
||||
out_data = undefined;
|
||||
poll_option.trigger("click");
|
||||
$poll_option.trigger("click");
|
||||
assert.deepEqual(out_data, undefined);
|
||||
}
|
||||
|
||||
@@ -298,13 +298,13 @@ run_test("activate another person poll", ({mock_template}) => {
|
||||
},
|
||||
];
|
||||
|
||||
widget_elem.handle_events(vote_events);
|
||||
$widget_elem.handle_events(vote_events);
|
||||
|
||||
{
|
||||
/* Testing data sent to server on voting */
|
||||
poll_vote_button.attr("data-key", "100,1");
|
||||
$poll_vote_button.attr("data-key", "100,1");
|
||||
out_data = undefined;
|
||||
poll_vote_button.trigger("click");
|
||||
$poll_vote_button.trigger("click");
|
||||
assert.deepEqual(out_data, {type: "vote", key: "100,1", vote: 1});
|
||||
}
|
||||
|
||||
@@ -318,20 +318,20 @@ run_test("activate another person poll", ({mock_template}) => {
|
||||
},
|
||||
];
|
||||
|
||||
widget_elem.handle_events(add_question_event);
|
||||
$widget_elem.handle_events(add_question_event);
|
||||
});
|
||||
|
||||
run_test("activate own poll", ({mock_template}) => {
|
||||
mock_template("widgets/poll_widget.hbs", false, () => "widgets/poll_widget");
|
||||
mock_template("widgets/poll_widget_results.hbs", false, () => "widgets/poll_widget_results");
|
||||
|
||||
const widget_elem = $("<div>").addClass("widget-content");
|
||||
const $widget_elem = $("<div>").addClass("widget-content");
|
||||
let out_data;
|
||||
const callback = (data) => {
|
||||
out_data = data;
|
||||
};
|
||||
const opts = {
|
||||
elem: widget_elem,
|
||||
$elem: $widget_elem,
|
||||
callback,
|
||||
message: {
|
||||
sender_id: me.user_id,
|
||||
@@ -342,59 +342,59 @@ run_test("activate own poll", ({mock_template}) => {
|
||||
};
|
||||
|
||||
const set_widget_find_result = (selector) => {
|
||||
const elem = $.create(selector);
|
||||
widget_elem.set_find_results(selector, elem);
|
||||
return elem;
|
||||
const $elem = $.create(selector);
|
||||
$widget_elem.set_find_results(selector, $elem);
|
||||
return $elem;
|
||||
};
|
||||
|
||||
set_widget_find_result("button.poll-option");
|
||||
const poll_option_input = set_widget_find_result("input.poll-option");
|
||||
const widget_option_container = set_widget_find_result("ul.poll-widget");
|
||||
const $poll_option_input = set_widget_find_result("input.poll-option");
|
||||
const $widget_option_container = set_widget_find_result("ul.poll-widget");
|
||||
|
||||
const poll_question_submit = set_widget_find_result("button.poll-question-check");
|
||||
const poll_edit_question = set_widget_find_result(".poll-edit-question");
|
||||
const poll_question_input = set_widget_find_result("input.poll-question");
|
||||
const poll_question_header = set_widget_find_result(".poll-question-header");
|
||||
const poll_question_container = set_widget_find_result(".poll-question-bar");
|
||||
const poll_option_container = set_widget_find_result(".poll-option-bar");
|
||||
const $poll_question_submit = set_widget_find_result("button.poll-question-check");
|
||||
const $poll_edit_question = set_widget_find_result(".poll-edit-question");
|
||||
const $poll_question_input = set_widget_find_result("input.poll-question");
|
||||
const $poll_question_header = set_widget_find_result(".poll-question-header");
|
||||
const $poll_question_container = set_widget_find_result(".poll-question-bar");
|
||||
const $poll_option_container = set_widget_find_result(".poll-option-bar");
|
||||
|
||||
set_widget_find_result("button.poll-vote");
|
||||
const poll_please_wait = set_widget_find_result(".poll-please-wait");
|
||||
const poll_author_help = set_widget_find_result(".poll-author-help");
|
||||
const $poll_please_wait = set_widget_find_result(".poll-please-wait");
|
||||
const $poll_author_help = set_widget_find_result(".poll-author-help");
|
||||
|
||||
set_widget_find_result("button.poll-question-remove");
|
||||
|
||||
function assert_visibility() {
|
||||
assert.ok(poll_option_container.visible());
|
||||
assert.ok(poll_question_header.visible());
|
||||
assert.ok(!poll_question_container.visible());
|
||||
assert.ok(poll_edit_question.visible());
|
||||
assert.ok(!poll_please_wait.visible());
|
||||
assert.ok(!poll_author_help.visible());
|
||||
assert.ok($poll_option_container.visible());
|
||||
assert.ok($poll_question_header.visible());
|
||||
assert.ok(!$poll_question_container.visible());
|
||||
assert.ok($poll_edit_question.visible());
|
||||
assert.ok(!$poll_please_wait.visible());
|
||||
assert.ok(!$poll_author_help.visible());
|
||||
}
|
||||
|
||||
poll_widget.activate(opts);
|
||||
|
||||
assert_visibility();
|
||||
assert.ok(!poll_question_submit.visible());
|
||||
assert.ok(!$poll_question_submit.visible());
|
||||
|
||||
assert.equal(widget_elem.html(), "widgets/poll_widget");
|
||||
assert.equal(widget_option_container.html(), "widgets/poll_widget_results");
|
||||
assert.equal(poll_question_header.text(), "Where to go?");
|
||||
assert.equal($widget_elem.html(), "widgets/poll_widget");
|
||||
assert.equal($widget_option_container.html(), "widgets/poll_widget_results");
|
||||
assert.equal($poll_question_header.text(), "Where to go?");
|
||||
|
||||
{
|
||||
/* Testing data sent to server on editing question */
|
||||
poll_question_input.val("Is it new?");
|
||||
$poll_question_input.val("Is it new?");
|
||||
out_data = undefined;
|
||||
poll_question_submit.trigger("click");
|
||||
$poll_question_submit.trigger("click");
|
||||
assert.deepEqual(out_data, {type: "question", question: "Is it new?"});
|
||||
|
||||
assert_visibility();
|
||||
assert.ok(poll_question_submit.visible());
|
||||
assert.ok($poll_question_submit.visible());
|
||||
|
||||
poll_option_input.val("");
|
||||
$poll_option_input.val("");
|
||||
out_data = undefined;
|
||||
poll_question_submit.trigger("click");
|
||||
$poll_question_submit.trigger("click");
|
||||
assert.deepEqual(out_data, undefined);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -146,9 +146,9 @@ test_ui("sender_hover", ({override, mock_template}) => {
|
||||
assert.equal(msg_id, message.id);
|
||||
};
|
||||
|
||||
const target = $.create("click target");
|
||||
const $target = $.create("click target");
|
||||
|
||||
target.closest = (sel) => {
|
||||
$target.closest = (sel) => {
|
||||
assert.equal(sel, ".message_row");
|
||||
return {};
|
||||
};
|
||||
@@ -173,6 +173,7 @@ test_ui("sender_hover", ({override, mock_template}) => {
|
||||
can_set_away: false,
|
||||
can_revoke_away: false,
|
||||
can_mute: true,
|
||||
can_manage_user: false,
|
||||
can_unmute: false,
|
||||
user_full_name: "Alice Smith",
|
||||
user_email: "alice@example.com",
|
||||
@@ -198,14 +199,13 @@ test_ui("sender_hover", ({override, mock_template}) => {
|
||||
user_mention_syntax: "@**Alice Smith**",
|
||||
date_joined: undefined,
|
||||
spectator_view: false,
|
||||
show_manage_user_option: false,
|
||||
});
|
||||
return "content-html";
|
||||
});
|
||||
|
||||
$.create(".user_popover_email", {children: []});
|
||||
const image_stubber = make_image_stubber();
|
||||
handler.call(target, e);
|
||||
handler.call($target, e);
|
||||
|
||||
const avatar_img = image_stubber.get(0);
|
||||
assert.equal(avatar_img.src.toString(), "/avatar/42/medium");
|
||||
@@ -216,7 +216,7 @@ test_ui("sender_hover", ({override, mock_template}) => {
|
||||
test_ui("actions_popover", ({override, override_rewire, mock_template}) => {
|
||||
override($.fn, "popover", noop);
|
||||
|
||||
const target = $.create("click target");
|
||||
const $target = $.create("click target");
|
||||
|
||||
const handler = $("#main_div").get_on_handler("click", ".actions_hover");
|
||||
|
||||
@@ -241,7 +241,7 @@ test_ui("actions_popover", ({override, override_rewire, mock_template}) => {
|
||||
|
||||
override_rewire(message_edit, "get_editability", () => 4);
|
||||
|
||||
target.closest = (sel) => {
|
||||
$target.closest = (sel) => {
|
||||
assert.equal(sel, ".message_row");
|
||||
return {
|
||||
toggleClass: noop,
|
||||
@@ -257,5 +257,5 @@ test_ui("actions_popover", ({override, override_rewire, mock_template}) => {
|
||||
return "actions-content";
|
||||
});
|
||||
|
||||
handler.call(target, e);
|
||||
handler.call($target, e);
|
||||
});
|
||||
|
||||
@@ -361,46 +361,46 @@ test("sending", ({override, override_rewire}) => {
|
||||
});
|
||||
|
||||
test("set_reaction_count", () => {
|
||||
const count_element = $.create("count-stub");
|
||||
const reaction_element = $.create("reaction-stub");
|
||||
const $count_element = $.create("count-stub");
|
||||
const $reaction_element = $.create("reaction-stub");
|
||||
|
||||
reaction_element.set_find_results(".message_reaction_count", count_element);
|
||||
$reaction_element.set_find_results(".message_reaction_count", $count_element);
|
||||
|
||||
reactions.set_reaction_count(reaction_element, 5);
|
||||
reactions.set_reaction_count($reaction_element, 5);
|
||||
|
||||
assert.equal(count_element.text(), "5");
|
||||
assert.equal($count_element.text(), "5");
|
||||
});
|
||||
|
||||
test("find_reaction", ({override_rewire}) => {
|
||||
const message_id = 99;
|
||||
const local_id = "unicode_emoji,1f44b";
|
||||
const reaction_section = $.create("section-stub");
|
||||
const $reaction_section = $.create("section-stub");
|
||||
|
||||
const reaction_stub = "reaction-stub";
|
||||
reaction_section.set_find_results(
|
||||
$reaction_section.set_find_results(
|
||||
`[data-reaction-id='${CSS.escape(local_id)}']`,
|
||||
reaction_stub,
|
||||
);
|
||||
|
||||
override_rewire(reactions, "get_reaction_section", (arg) => {
|
||||
assert.equal(arg, message_id);
|
||||
return reaction_section;
|
||||
return $reaction_section;
|
||||
});
|
||||
|
||||
assert.equal(reactions.find_reaction(message_id, local_id), reaction_stub);
|
||||
});
|
||||
|
||||
test("get_reaction_section", () => {
|
||||
const message_table = $.create(".message_table");
|
||||
const message_row = $.create("some-message-row");
|
||||
const message_reactions = $.create("our-reactions-section");
|
||||
const $message_table = $.create(".message_table");
|
||||
const $message_row = $.create("some-message-row");
|
||||
const $message_reactions = $.create("our-reactions-section");
|
||||
|
||||
message_table.set_find_results(`[zid='${CSS.escape(555)}']`, message_row);
|
||||
message_row.set_find_results(".message_reactions", message_reactions);
|
||||
$message_table.set_find_results(`[zid='${CSS.escape(555)}']`, $message_row);
|
||||
$message_row.set_find_results(".message_reactions", $message_reactions);
|
||||
|
||||
const section = reactions.get_reaction_section(555);
|
||||
const $section = reactions.get_reaction_section(555);
|
||||
|
||||
assert.equal(section, message_reactions);
|
||||
assert.equal($section, $message_reactions);
|
||||
});
|
||||
|
||||
test("emoji_reaction_title", ({override}) => {
|
||||
@@ -599,14 +599,14 @@ test("view.insert_new_reaction (me w/unicode emoji)", ({override_rewire, mock_te
|
||||
user_id: alice.user_id,
|
||||
};
|
||||
|
||||
const message_reactions = $.create("our-reactions");
|
||||
const $message_reactions = $.create("our-reactions");
|
||||
|
||||
override_rewire(reactions, "get_reaction_section", (message_id) => {
|
||||
assert.equal(message_id, opts.message_id);
|
||||
return message_reactions;
|
||||
return $message_reactions;
|
||||
});
|
||||
|
||||
message_reactions.find = (selector) => {
|
||||
$message_reactions.find = (selector) => {
|
||||
assert.equal(selector, ".reaction_button");
|
||||
return "reaction-button-stub";
|
||||
};
|
||||
@@ -624,11 +624,11 @@ test("view.insert_new_reaction (me w/unicode emoji)", ({override_rewire, mock_te
|
||||
reaction_type: opts.reaction_type,
|
||||
is_realm_emoji: false,
|
||||
});
|
||||
return "<new reaction html>";
|
||||
return "<new-reaction-stub>";
|
||||
});
|
||||
|
||||
let insert_called;
|
||||
$("<new reaction html>").insertBefore = (element) => {
|
||||
$("<new-reaction-stub>").insertBefore = (element) => {
|
||||
assert.equal(element, "reaction-button-stub");
|
||||
insert_called = true;
|
||||
};
|
||||
@@ -646,14 +646,14 @@ test("view.insert_new_reaction (them w/zulip emoji)", ({override_rewire, mock_te
|
||||
user_id: bob.user_id,
|
||||
};
|
||||
|
||||
const message_reactions = $.create("our-reactions");
|
||||
const $message_reactions = $.create("our-reactions");
|
||||
|
||||
override_rewire(reactions, "get_reaction_section", (message_id) => {
|
||||
assert.equal(message_id, opts.message_id);
|
||||
return message_reactions;
|
||||
return $message_reactions;
|
||||
});
|
||||
|
||||
message_reactions.find = (selector) => {
|
||||
$message_reactions.find = (selector) => {
|
||||
assert.equal(selector, ".reaction_button");
|
||||
return "reaction-button-stub";
|
||||
};
|
||||
@@ -673,11 +673,11 @@ test("view.insert_new_reaction (them w/zulip emoji)", ({override_rewire, mock_te
|
||||
still_url: undefined,
|
||||
reaction_type: opts.reaction_type,
|
||||
});
|
||||
return "<new reaction html>";
|
||||
return "<new-reaction-stub>";
|
||||
});
|
||||
|
||||
let insert_called;
|
||||
$("<new reaction html>").insertBefore = (element) => {
|
||||
$("<new-reaction-stub>").insertBefore = (element) => {
|
||||
assert.equal(element, "reaction-button-stub");
|
||||
insert_called = true;
|
||||
};
|
||||
@@ -696,24 +696,24 @@ test("view.update_existing_reaction (me)", ({override_rewire}) => {
|
||||
user_list: [alice.user_id, bob.user_id],
|
||||
};
|
||||
|
||||
const our_reaction = $.create("our-reaction-stub");
|
||||
const $our_reaction = $.create("our-reaction-stub");
|
||||
|
||||
override_rewire(reactions, "find_reaction", (message_id, local_id) => {
|
||||
assert.equal(message_id, opts.message_id);
|
||||
assert.equal(local_id, "unicode_emoji,1f3b1");
|
||||
return our_reaction;
|
||||
return $our_reaction;
|
||||
});
|
||||
|
||||
override_rewire(reactions, "set_reaction_count", (reaction, count) => {
|
||||
assert.equal(reaction, our_reaction);
|
||||
assert.equal(reaction, $our_reaction);
|
||||
assert.equal(count, 2);
|
||||
});
|
||||
|
||||
reactions.view.update_existing_reaction(opts);
|
||||
|
||||
assert.ok(our_reaction.hasClass("reacted"));
|
||||
assert.ok($our_reaction.hasClass("reacted"));
|
||||
assert.equal(
|
||||
our_reaction.attr("aria-label"),
|
||||
$our_reaction.attr("aria-label"),
|
||||
"translated: You (click to remove) and Bob van Roberts reacted with :8ball:",
|
||||
);
|
||||
});
|
||||
@@ -728,24 +728,24 @@ test("view.update_existing_reaction (them)", ({override_rewire}) => {
|
||||
user_list: [alice.user_id, bob.user_id, cali.user_id, alexus.user_id],
|
||||
};
|
||||
|
||||
const our_reaction = $.create("our-reaction-stub");
|
||||
const $our_reaction = $.create("our-reaction-stub");
|
||||
|
||||
override_rewire(reactions, "find_reaction", (message_id, local_id) => {
|
||||
assert.equal(message_id, opts.message_id);
|
||||
assert.equal(local_id, "unicode_emoji,1f3b1");
|
||||
return our_reaction;
|
||||
return $our_reaction;
|
||||
});
|
||||
|
||||
override_rewire(reactions, "set_reaction_count", (reaction, count) => {
|
||||
assert.equal(reaction, our_reaction);
|
||||
assert.equal(reaction, $our_reaction);
|
||||
assert.equal(count, 4);
|
||||
});
|
||||
|
||||
reactions.view.update_existing_reaction(opts);
|
||||
|
||||
assert.ok(!our_reaction.hasClass("reacted"));
|
||||
assert.ok(!$our_reaction.hasClass("reacted"));
|
||||
assert.equal(
|
||||
our_reaction.attr("aria-label"),
|
||||
$our_reaction.attr("aria-label"),
|
||||
"translated: You (click to remove), Bob van Roberts, Cali and Alexus reacted with :8ball:",
|
||||
);
|
||||
});
|
||||
@@ -760,25 +760,25 @@ test("view.remove_reaction (me)", ({override_rewire}) => {
|
||||
user_list: [bob.user_id, cali.user_id],
|
||||
};
|
||||
|
||||
const our_reaction = $.create("our-reaction-stub");
|
||||
our_reaction.addClass("reacted");
|
||||
const $our_reaction = $.create("our-reaction-stub");
|
||||
$our_reaction.addClass("reacted");
|
||||
|
||||
override_rewire(reactions, "find_reaction", (message_id, local_id) => {
|
||||
assert.equal(message_id, opts.message_id);
|
||||
assert.equal(local_id, "unicode_emoji,1f3b1");
|
||||
return our_reaction;
|
||||
return $our_reaction;
|
||||
});
|
||||
|
||||
override_rewire(reactions, "set_reaction_count", (reaction, count) => {
|
||||
assert.equal(reaction, our_reaction);
|
||||
assert.equal(reaction, $our_reaction);
|
||||
assert.equal(count, 2);
|
||||
});
|
||||
|
||||
reactions.view.remove_reaction(opts);
|
||||
|
||||
assert.ok(!our_reaction.hasClass("reacted"));
|
||||
assert.ok(!$our_reaction.hasClass("reacted"));
|
||||
assert.equal(
|
||||
our_reaction.attr("aria-label"),
|
||||
$our_reaction.attr("aria-label"),
|
||||
"translated: Bob van Roberts and Cali reacted with :8ball:",
|
||||
);
|
||||
});
|
||||
@@ -793,26 +793,26 @@ test("view.remove_reaction (them)", ({override_rewire}) => {
|
||||
user_list: [alice.user_id],
|
||||
};
|
||||
|
||||
const our_reaction = $.create("our-reaction-stub");
|
||||
our_reaction.addClass("reacted");
|
||||
const $our_reaction = $.create("our-reaction-stub");
|
||||
$our_reaction.addClass("reacted");
|
||||
|
||||
override_rewire(reactions, "find_reaction", (message_id, local_id) => {
|
||||
assert.equal(message_id, opts.message_id);
|
||||
assert.equal(local_id, "unicode_emoji,1f3b1");
|
||||
return our_reaction;
|
||||
return $our_reaction;
|
||||
});
|
||||
|
||||
override_rewire(reactions, "set_reaction_count", (reaction, count) => {
|
||||
assert.equal(reaction, our_reaction);
|
||||
assert.equal(reaction, $our_reaction);
|
||||
assert.equal(count, 1);
|
||||
});
|
||||
|
||||
our_reaction.addClass("reacted");
|
||||
$our_reaction.addClass("reacted");
|
||||
reactions.view.remove_reaction(opts);
|
||||
|
||||
assert.ok(our_reaction.hasClass("reacted"));
|
||||
assert.ok($our_reaction.hasClass("reacted"));
|
||||
assert.equal(
|
||||
our_reaction.attr("aria-label"),
|
||||
$our_reaction.attr("aria-label"),
|
||||
"translated: You (click to remove) reacted with :8ball:",
|
||||
);
|
||||
});
|
||||
@@ -827,16 +827,16 @@ test("view.remove_reaction (last person)", ({override_rewire}) => {
|
||||
user_list: [],
|
||||
};
|
||||
|
||||
const our_reaction = $.create("our-reaction-stub");
|
||||
const $our_reaction = $.create("our-reaction-stub");
|
||||
|
||||
override_rewire(reactions, "find_reaction", (message_id, local_id) => {
|
||||
assert.equal(message_id, opts.message_id);
|
||||
assert.equal(local_id, "unicode_emoji,1f3b1");
|
||||
return our_reaction;
|
||||
return $our_reaction;
|
||||
});
|
||||
|
||||
let removed;
|
||||
our_reaction.remove = () => {
|
||||
$our_reaction.remove = () => {
|
||||
removed = true;
|
||||
};
|
||||
reactions.view.remove_reaction(opts);
|
||||
|
||||
@@ -97,9 +97,10 @@ mock_esm("../../static/js/muted_topics", {
|
||||
return false;
|
||||
},
|
||||
});
|
||||
mock_esm("../../static/js/narrow", {
|
||||
const narrow = mock_esm("../../static/js/narrow", {
|
||||
set_narrow_title: noop,
|
||||
hide_mark_as_read_turned_off_banner: noop,
|
||||
has_shown_message_list_view: true,
|
||||
});
|
||||
mock_esm("../../static/js/recent_senders", {
|
||||
get_topic_recent_senders: () => [1, 2],
|
||||
@@ -115,7 +116,7 @@ mock_esm("../../static/js/stream_list", {
|
||||
handle_narrow_deactivated: noop,
|
||||
});
|
||||
mock_esm("../../static/js/timerender", {
|
||||
format_time_modern: () => "Just now",
|
||||
last_seen_status_from_date: () => "Just now",
|
||||
get_full_datetime: () => "date at time",
|
||||
});
|
||||
mock_esm("../../static/js/sub_store", {
|
||||
@@ -323,9 +324,9 @@ function stub_out_filter_buttons() {
|
||||
// See show_selected_filters() and set_filter() in the
|
||||
// implementation.
|
||||
for (const filter of ["all", "unread", "muted", "participated"]) {
|
||||
const stub = $.create(`filter-${filter}-stub`);
|
||||
const $stub = $.create(`filter-${filter}-stub`);
|
||||
const selector = `[data-filter="${filter}"]`;
|
||||
$("#recent_topics_filter_buttons").set_find_results(selector, stub);
|
||||
$("#recent_topics_filter_buttons").set_find_results(selector, $stub);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -338,7 +339,9 @@ function test(label, f) {
|
||||
});
|
||||
}
|
||||
|
||||
test("test_recent_topics_show", ({mock_template}) => {
|
||||
test("test_recent_topics_show", ({mock_template, override}) => {
|
||||
override(narrow, "save_pre_narrow_offset_for_reload", () => {});
|
||||
|
||||
// Note: unread count and urls are fake,
|
||||
// since they are generated in external libraries
|
||||
// and are not to be tested here.
|
||||
|
||||
@@ -104,12 +104,12 @@ const get_content_element = () => {
|
||||
};
|
||||
|
||||
run_test("misc_helpers", () => {
|
||||
const elem = $.create("user-mention");
|
||||
rm.set_name_in_mention_element(elem, "Aaron");
|
||||
assert.equal(elem.text(), "@Aaron");
|
||||
elem.addClass("silent");
|
||||
rm.set_name_in_mention_element(elem, "Aaron, but silent");
|
||||
assert.equal(elem.text(), "Aaron, but silent");
|
||||
const $elem = $.create("user-mention");
|
||||
rm.set_name_in_mention_element($elem, "Aaron");
|
||||
assert.equal($elem.text(), "@Aaron");
|
||||
$elem.addClass("silent");
|
||||
rm.set_name_in_mention_element($elem, "Aaron, but silent");
|
||||
assert.equal($elem.text(), "Aaron, but silent");
|
||||
});
|
||||
|
||||
run_test("user-mention", () => {
|
||||
@@ -423,8 +423,8 @@ function test_code_playground(mock_template, viewing_code) {
|
||||
|
||||
return {
|
||||
prepends,
|
||||
copy_code: $copy_code_button,
|
||||
view_code: $view_code_in_playground,
|
||||
$copy_code: $copy_code_button,
|
||||
$view_code: $view_code_in_playground,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -434,12 +434,12 @@ run_test("code playground none", ({override, mock_template}) => {
|
||||
return undefined;
|
||||
});
|
||||
|
||||
const {prepends, copy_code, view_code} = test_code_playground(mock_template, false);
|
||||
assert.deepEqual(prepends, [copy_code]);
|
||||
const {prepends, $copy_code, $view_code} = test_code_playground(mock_template, false);
|
||||
assert.deepEqual(prepends, [$copy_code]);
|
||||
assert_clipboard_setup();
|
||||
|
||||
assert.equal(view_code.attr("data-tippy-content"), undefined);
|
||||
assert.equal(view_code.attr("aria-label"), undefined);
|
||||
assert.equal($view_code.attr("data-tippy-content"), undefined);
|
||||
assert.equal($view_code.attr("aria-label"), undefined);
|
||||
});
|
||||
|
||||
run_test("code playground single", ({override, mock_template}) => {
|
||||
@@ -448,16 +448,16 @@ run_test("code playground single", ({override, mock_template}) => {
|
||||
return [{name: "Some Javascript Playground"}];
|
||||
});
|
||||
|
||||
const {prepends, copy_code, view_code} = test_code_playground(mock_template, true);
|
||||
assert.deepEqual(prepends, [view_code, copy_code]);
|
||||
const {prepends, $copy_code, $view_code} = test_code_playground(mock_template, true);
|
||||
assert.deepEqual(prepends, [$view_code, $copy_code]);
|
||||
assert_clipboard_setup();
|
||||
|
||||
assert.equal(
|
||||
view_code.attr("data-tippy-content"),
|
||||
$view_code.attr("data-tippy-content"),
|
||||
"translated: View in Some Javascript Playground",
|
||||
);
|
||||
assert.equal(view_code.attr("aria-label"), "translated: View in Some Javascript Playground");
|
||||
assert.equal(view_code.attr("aria-haspopup"), undefined);
|
||||
assert.equal($view_code.attr("aria-label"), "translated: View in Some Javascript Playground");
|
||||
assert.equal($view_code.attr("aria-haspopup"), undefined);
|
||||
});
|
||||
|
||||
run_test("code playground multiple", ({override, mock_template}) => {
|
||||
@@ -466,13 +466,13 @@ run_test("code playground multiple", ({override, mock_template}) => {
|
||||
return ["whatever", "whatever"];
|
||||
});
|
||||
|
||||
const {prepends, copy_code, view_code} = test_code_playground(mock_template, true);
|
||||
assert.deepEqual(prepends, [view_code, copy_code]);
|
||||
const {prepends, $copy_code, $view_code} = test_code_playground(mock_template, true);
|
||||
assert.deepEqual(prepends, [$view_code, $copy_code]);
|
||||
assert_clipboard_setup();
|
||||
|
||||
assert.equal(view_code.attr("data-tippy-content"), "translated: View in playground");
|
||||
assert.equal(view_code.attr("aria-label"), "translated: View in playground");
|
||||
assert.equal(view_code.attr("aria-haspopup"), "true");
|
||||
assert.equal($view_code.attr("data-tippy-content"), "translated: View in playground");
|
||||
assert.equal($view_code.attr("aria-label"), "translated: View in playground");
|
||||
assert.equal($view_code.attr("aria-haspopup"), "true");
|
||||
});
|
||||
|
||||
run_test("rtl", () => {
|
||||
|
||||
@@ -129,20 +129,20 @@ run_test("get_direction", () => {
|
||||
});
|
||||
|
||||
run_test("set_rtl_class_for_textarea rtl", () => {
|
||||
const textarea = $.create("some-textarea");
|
||||
assert.ok(!textarea.hasClass("rtl"));
|
||||
const $textarea = $.create("some-textarea");
|
||||
assert.ok(!$textarea.hasClass("rtl"));
|
||||
const text = "```quote\nمرحبا";
|
||||
textarea.val(text);
|
||||
rtl.set_rtl_class_for_textarea(textarea);
|
||||
assert.ok(textarea.hasClass("rtl"));
|
||||
$textarea.val(text);
|
||||
rtl.set_rtl_class_for_textarea($textarea);
|
||||
assert.ok($textarea.hasClass("rtl"));
|
||||
});
|
||||
|
||||
run_test("set_rtl_class_for_textarea ltr", () => {
|
||||
const textarea = $.create("some-textarea");
|
||||
textarea.addClass("rtl");
|
||||
assert.ok(textarea.hasClass("rtl"));
|
||||
const $textarea = $.create("some-textarea");
|
||||
$textarea.addClass("rtl");
|
||||
assert.ok($textarea.hasClass("rtl"));
|
||||
const text = "```quote\nEnglish text";
|
||||
textarea.val(text);
|
||||
rtl.set_rtl_class_for_textarea(textarea);
|
||||
assert.ok(!textarea.hasClass("rtl"));
|
||||
$textarea.val(text);
|
||||
rtl.set_rtl_class_for_textarea($textarea);
|
||||
assert.ok(!$textarea.hasClass("rtl"));
|
||||
});
|
||||
|
||||
@@ -89,7 +89,7 @@ run_test("scroll_delta", () => {
|
||||
});
|
||||
|
||||
run_test("scroll_element_into_container", () => {
|
||||
const container = (function () {
|
||||
const $container = (function () {
|
||||
let top = 3;
|
||||
return {
|
||||
height: () => 100,
|
||||
@@ -103,21 +103,21 @@ run_test("scroll_element_into_container", () => {
|
||||
};
|
||||
})();
|
||||
|
||||
const elem1 = {
|
||||
const $elem1 = {
|
||||
innerHeight: () => 25,
|
||||
position: () => ({
|
||||
top: 0,
|
||||
}),
|
||||
};
|
||||
scroll_util.scroll_element_into_container(elem1, container);
|
||||
assert.equal(container.scrollTop(), 3);
|
||||
scroll_util.scroll_element_into_container($elem1, $container);
|
||||
assert.equal($container.scrollTop(), 3);
|
||||
|
||||
const elem2 = {
|
||||
const $elem2 = {
|
||||
innerHeight: () => 15,
|
||||
position: () => ({
|
||||
top: 250,
|
||||
}),
|
||||
};
|
||||
scroll_util.scroll_element_into_container(elem2, container);
|
||||
assert.equal(container.scrollTop(), 250 - 100 + 3 + 15);
|
||||
scroll_util.scroll_element_into_container($elem2, $container);
|
||||
assert.equal($container.scrollTop(), 250 - 100 + 3 + 15);
|
||||
});
|
||||
|
||||
@@ -51,50 +51,50 @@ test("clear_search_form", () => {
|
||||
});
|
||||
|
||||
test("update_button_visibility", () => {
|
||||
const search_query = $("#search_query");
|
||||
const search_button = $(".search_button");
|
||||
const $search_query = $("#search_query");
|
||||
const $search_button = $(".search_button");
|
||||
|
||||
search_query.is = () => false;
|
||||
search_query.val("");
|
||||
$search_query.is = () => false;
|
||||
$search_query.val("");
|
||||
narrow_state.active = () => false;
|
||||
search_button.prop("disabled", true);
|
||||
$search_button.prop("disabled", true);
|
||||
search.update_button_visibility();
|
||||
assert.ok(search_button.prop("disabled"));
|
||||
assert.ok($search_button.prop("disabled"));
|
||||
|
||||
search_query.is = () => true;
|
||||
search_query.val("");
|
||||
$search_query.is = () => true;
|
||||
$search_query.val("");
|
||||
narrow_state.active = () => false;
|
||||
search_button.prop("disabled", true);
|
||||
$search_button.prop("disabled", true);
|
||||
search.update_button_visibility();
|
||||
assert.ok(!search_button.prop("disabled"));
|
||||
assert.ok(!$search_button.prop("disabled"));
|
||||
|
||||
search_query.is = () => false;
|
||||
search_query.val("Test search term");
|
||||
$search_query.is = () => false;
|
||||
$search_query.val("Test search term");
|
||||
narrow_state.active = () => false;
|
||||
search_button.prop("disabled", true);
|
||||
$search_button.prop("disabled", true);
|
||||
search.update_button_visibility();
|
||||
assert.ok(!search_button.prop("disabled"));
|
||||
assert.ok(!$search_button.prop("disabled"));
|
||||
|
||||
search_query.is = () => false;
|
||||
search_query.val("");
|
||||
$search_query.is = () => false;
|
||||
$search_query.val("");
|
||||
narrow_state.active = () => true;
|
||||
search_button.prop("disabled", true);
|
||||
$search_button.prop("disabled", true);
|
||||
search.update_button_visibility();
|
||||
assert.ok(!search_button.prop("disabled"));
|
||||
assert.ok(!$search_button.prop("disabled"));
|
||||
});
|
||||
|
||||
test("initialize", () => {
|
||||
const search_query_box = $("#search_query");
|
||||
const searchbox_form = $("#searchbox_form");
|
||||
const search_button = $(".search_button");
|
||||
const searchbox = $("#searchbox");
|
||||
const $search_query_box = $("#search_query");
|
||||
const $searchbox_form = $("#searchbox_form");
|
||||
const $search_button = $(".search_button");
|
||||
const $searchbox = $("#searchbox");
|
||||
|
||||
search_query_box[0] = "stub";
|
||||
$search_query_box[0] = "stub";
|
||||
|
||||
search_pill.get_search_string_for_current_filter = () => "is:starred";
|
||||
|
||||
search_suggestion.max_num_of_search_results = 99;
|
||||
search_query_box.typeahead = (opts) => {
|
||||
$search_query_box.typeahead = (opts) => {
|
||||
assert.equal(opts.fixed, true);
|
||||
assert.equal(opts.items, 99);
|
||||
assert.equal(opts.naturalSearch, true);
|
||||
@@ -144,7 +144,7 @@ test("initialize", () => {
|
||||
let operators;
|
||||
let is_blurred;
|
||||
let is_append_search_string_called;
|
||||
search_query_box.on("blur", () => {
|
||||
$search_query_box.on("blur", () => {
|
||||
is_blurred = true;
|
||||
});
|
||||
search_pill.append_search_string = () => {
|
||||
@@ -154,7 +154,7 @@ test("initialize", () => {
|
||||
const _setup = (search_box_val) => {
|
||||
is_blurred = false;
|
||||
is_append_search_string_called = false;
|
||||
search_query_box.val(search_box_val);
|
||||
$search_query_box.val(search_box_val);
|
||||
Filter.parse = (search_string) => {
|
||||
assert.equal(search_string, search_box_val);
|
||||
return operators;
|
||||
@@ -199,34 +199,35 @@ test("initialize", () => {
|
||||
assert.ok(!is_blurred);
|
||||
assert.ok(is_append_search_string_called);
|
||||
|
||||
search_query_box.off("blur");
|
||||
$search_query_box.off("blur");
|
||||
}
|
||||
};
|
||||
|
||||
search.initialize();
|
||||
|
||||
const search_pill_stub = $.create(".pill");
|
||||
search_pill_stub.closest = () => ({data: noop});
|
||||
const $search_pill_stub = $.create(".pill");
|
||||
$search_pill_stub.closest = () => ({data: noop});
|
||||
const stub_event = {
|
||||
relatedTarget: search_pill_stub,
|
||||
// FIXME: event.relatedTarget should not be a jQuery object
|
||||
relatedTarget: $search_pill_stub,
|
||||
};
|
||||
search_query_box.val("test string");
|
||||
$search_query_box.val("test string");
|
||||
narrow_state.search_string = () => "ver";
|
||||
search_query_box.trigger(new $.Event("blur", stub_event));
|
||||
assert.equal(search_query_box.val(), "test string");
|
||||
$search_query_box.trigger(new $.Event("blur", stub_event));
|
||||
assert.equal($search_query_box.val(), "test string");
|
||||
|
||||
let css_args;
|
||||
searchbox.css = (args) => {
|
||||
$searchbox.css = (args) => {
|
||||
css_args = args;
|
||||
};
|
||||
searchbox.trigger("focusout");
|
||||
$searchbox.trigger("focusout");
|
||||
assert.deepEqual(css_args, {"box-shadow": "unset"});
|
||||
|
||||
search.__Rewire__("is_using_input_method", false);
|
||||
searchbox_form.trigger("compositionend");
|
||||
$searchbox_form.trigger("compositionend");
|
||||
assert.ok(search.is_using_input_method);
|
||||
|
||||
const keydown = searchbox_form.get_on_handler("keydown");
|
||||
const keydown = $searchbox_form.get_on_handler("keydown");
|
||||
let default_prevented = false;
|
||||
let ev = {
|
||||
type: "keydown",
|
||||
@@ -235,7 +236,7 @@ test("initialize", () => {
|
||||
default_prevented = true;
|
||||
},
|
||||
};
|
||||
search_query_box.is = () => false;
|
||||
$search_query_box.is = () => false;
|
||||
assert.equal(keydown(ev), undefined);
|
||||
assert.ok(!default_prevented);
|
||||
|
||||
@@ -244,22 +245,22 @@ test("initialize", () => {
|
||||
assert.ok(!default_prevented);
|
||||
|
||||
ev.key = "Enter";
|
||||
search_query_box.is = () => true;
|
||||
$search_query_box.is = () => true;
|
||||
assert.equal(keydown(ev), undefined);
|
||||
assert.ok(default_prevented);
|
||||
|
||||
let operators;
|
||||
let is_blurred;
|
||||
narrow_state.active = () => false;
|
||||
search_query_box.off("blur");
|
||||
search_query_box.on("blur", () => {
|
||||
$search_query_box.off("blur");
|
||||
$search_query_box.on("blur", () => {
|
||||
is_blurred = true;
|
||||
});
|
||||
|
||||
const _setup = (search_box_val) => {
|
||||
is_blurred = false;
|
||||
search_button.prop("disabled", false);
|
||||
search_query_box.val(search_box_val);
|
||||
$search_button.prop("disabled", false);
|
||||
$search_query_box.val(search_box_val);
|
||||
Filter.parse = (search_string) => {
|
||||
assert.equal(search_string, search_box_val);
|
||||
return operators;
|
||||
@@ -284,41 +285,41 @@ test("initialize", () => {
|
||||
type: "keyup",
|
||||
which: 15,
|
||||
};
|
||||
search_query_box.is = () => false;
|
||||
searchbox_form.trigger(ev);
|
||||
$search_query_box.is = () => false;
|
||||
$searchbox_form.trigger(ev);
|
||||
|
||||
assert.ok(!is_blurred);
|
||||
assert.ok(!search_button.prop("disabled"));
|
||||
assert.ok(!$search_button.prop("disabled"));
|
||||
|
||||
ev.key = "Enter";
|
||||
search_query_box.is = () => false;
|
||||
searchbox_form.trigger(ev);
|
||||
$search_query_box.is = () => false;
|
||||
$searchbox_form.trigger(ev);
|
||||
|
||||
assert.ok(!is_blurred);
|
||||
assert.ok(!search_button.prop("disabled"));
|
||||
assert.ok(!$search_button.prop("disabled"));
|
||||
|
||||
ev.key = "Enter";
|
||||
search_query_box.is = () => true;
|
||||
searchbox_form.trigger(ev);
|
||||
$search_query_box.is = () => true;
|
||||
$searchbox_form.trigger(ev);
|
||||
assert.ok(is_blurred);
|
||||
|
||||
_setup("ver");
|
||||
search.__Rewire__("is_using_input_method", true);
|
||||
searchbox_form.trigger(ev);
|
||||
$searchbox_form.trigger(ev);
|
||||
// No change on Enter keyup event when using input tool
|
||||
assert.ok(!is_blurred);
|
||||
assert.ok(!search_button.prop("disabled"));
|
||||
assert.ok(!$search_button.prop("disabled"));
|
||||
|
||||
_setup("ver");
|
||||
ev.key = "Enter";
|
||||
search_query_box.is = () => true;
|
||||
searchbox_form.trigger(ev);
|
||||
$search_query_box.is = () => true;
|
||||
$searchbox_form.trigger(ev);
|
||||
assert.ok(is_blurred);
|
||||
assert.ok(!search_button.prop("disabled"));
|
||||
assert.ok(!$search_button.prop("disabled"));
|
||||
|
||||
search_button.prop("disabled", true);
|
||||
search_query_box.trigger("focus");
|
||||
assert.ok(!search_button.prop("disabled"));
|
||||
$search_button.prop("disabled", true);
|
||||
$search_query_box.trigger("focus");
|
||||
assert.ok(!$search_button.prop("disabled"));
|
||||
});
|
||||
|
||||
test("initiate_search", () => {
|
||||
@@ -345,9 +346,9 @@ test("initiate_search", () => {
|
||||
|
||||
$("#search_query")[0] = "stub";
|
||||
|
||||
const searchbox = $("#searchbox");
|
||||
const $searchbox = $("#searchbox");
|
||||
let css_args;
|
||||
searchbox.css = (args) => {
|
||||
$searchbox.css = (args) => {
|
||||
css_args = args;
|
||||
};
|
||||
|
||||
@@ -28,46 +28,58 @@ set_global("setTimeout", (func) => func());
|
||||
|
||||
const search = zrequire("search");
|
||||
|
||||
run_test("clear_search_form", () => {
|
||||
$("#search_query").val("noise");
|
||||
$("#search_query").trigger("focus");
|
||||
$(".search_button").prop("disabled", false);
|
||||
|
||||
search.clear_search_form();
|
||||
|
||||
assert.equal($("#search_query").is_focused(), false);
|
||||
assert.equal($("#search_query").val(), "");
|
||||
assert.equal($(".search_button").prop("disabled"), true);
|
||||
});
|
||||
|
||||
run_test("update_button_visibility", () => {
|
||||
const search_query = $("#search_query");
|
||||
const search_button = $(".search_button");
|
||||
const $search_query = $("#search_query");
|
||||
const $search_button = $(".search_button");
|
||||
|
||||
search_query.is = () => false;
|
||||
search_query.val("");
|
||||
$search_query.is = () => false;
|
||||
$search_query.val("");
|
||||
narrow_state.active = () => false;
|
||||
search_button.prop("disabled", true);
|
||||
$search_button.prop("disabled", true);
|
||||
search.update_button_visibility();
|
||||
assert.ok(search_button.prop("disabled"));
|
||||
assert.ok($search_button.prop("disabled"));
|
||||
|
||||
search_query.is = () => true;
|
||||
search_query.val("");
|
||||
$search_query.is = () => true;
|
||||
$search_query.val("");
|
||||
narrow_state.active = () => false;
|
||||
search_button.prop("disabled", true);
|
||||
$search_button.prop("disabled", true);
|
||||
search.update_button_visibility();
|
||||
assert.ok(!search_button.prop("disabled"));
|
||||
assert.ok(!$search_button.prop("disabled"));
|
||||
|
||||
search_query.is = () => false;
|
||||
search_query.val("Test search term");
|
||||
$search_query.is = () => false;
|
||||
$search_query.val("Test search term");
|
||||
narrow_state.active = () => false;
|
||||
search_button.prop("disabled", true);
|
||||
$search_button.prop("disabled", true);
|
||||
search.update_button_visibility();
|
||||
assert.ok(!search_button.prop("disabled"));
|
||||
assert.ok(!$search_button.prop("disabled"));
|
||||
|
||||
search_query.is = () => false;
|
||||
search_query.val("");
|
||||
$search_query.is = () => false;
|
||||
$search_query.val("");
|
||||
narrow_state.active = () => true;
|
||||
search_button.prop("disabled", true);
|
||||
$search_button.prop("disabled", true);
|
||||
search.update_button_visibility();
|
||||
assert.ok(!search_button.prop("disabled"));
|
||||
assert.ok(!$search_button.prop("disabled"));
|
||||
});
|
||||
|
||||
run_test("initialize", () => {
|
||||
const search_query_box = $("#search_query");
|
||||
const searchbox_form = $("#searchbox_form");
|
||||
const search_button = $(".search_button");
|
||||
const $search_query_box = $("#search_query");
|
||||
const $searchbox_form = $("#searchbox_form");
|
||||
const $search_button = $(".search_button");
|
||||
|
||||
search_suggestion.max_num_of_search_results = 999;
|
||||
search_query_box.typeahead = (opts) => {
|
||||
$search_query_box.typeahead = (opts) => {
|
||||
assert.equal(opts.fixed, true);
|
||||
assert.equal(opts.items, 999);
|
||||
assert.equal(opts.naturalSearch, true);
|
||||
@@ -115,13 +127,13 @@ run_test("initialize", () => {
|
||||
{
|
||||
let operators;
|
||||
let is_blurred;
|
||||
search_query_box.on("blur", () => {
|
||||
$search_query_box.on("blur", () => {
|
||||
is_blurred = true;
|
||||
});
|
||||
/* Test updater */
|
||||
const _setup = (search_box_val) => {
|
||||
is_blurred = false;
|
||||
search_query_box.val(search_box_val);
|
||||
$search_query_box.val(search_box_val);
|
||||
Filter.parse = (search_string) => {
|
||||
assert.equal(search_string, search_box_val);
|
||||
return operators;
|
||||
@@ -159,26 +171,26 @@ run_test("initialize", () => {
|
||||
assert.equal(opts.updater("stream:Verona"), "stream:Verona");
|
||||
assert.ok(!is_blurred);
|
||||
|
||||
search_query_box.off("blur");
|
||||
$search_query_box.off("blur");
|
||||
}
|
||||
};
|
||||
|
||||
search.initialize();
|
||||
|
||||
search_button.prop("disabled", true);
|
||||
search_query_box.trigger("focus");
|
||||
assert.ok(!search_button.prop("disabled"));
|
||||
$search_button.prop("disabled", true);
|
||||
$search_query_box.trigger("focus");
|
||||
assert.ok(!$search_button.prop("disabled"));
|
||||
|
||||
search_query_box.val("test string");
|
||||
$search_query_box.val("test string");
|
||||
narrow_state.search_string = () => "ver";
|
||||
search_query_box.trigger("blur");
|
||||
assert.equal(search_query_box.val(), "test string");
|
||||
$search_query_box.trigger("blur");
|
||||
assert.equal($search_query_box.val(), "test string");
|
||||
|
||||
search.__Rewire__("is_using_input_method", false);
|
||||
searchbox_form.trigger("compositionend");
|
||||
$searchbox_form.trigger("compositionend");
|
||||
assert.ok(search.is_using_input_method);
|
||||
|
||||
const keydown = searchbox_form.get_on_handler("keydown");
|
||||
const keydown = $searchbox_form.get_on_handler("keydown");
|
||||
let default_prevented = false;
|
||||
let ev = {
|
||||
type: "keydown",
|
||||
@@ -187,7 +199,7 @@ run_test("initialize", () => {
|
||||
default_prevented = true;
|
||||
},
|
||||
};
|
||||
search_query_box.is = () => false;
|
||||
$search_query_box.is = () => false;
|
||||
assert.equal(keydown(ev), undefined);
|
||||
assert.ok(!default_prevented);
|
||||
|
||||
@@ -196,7 +208,7 @@ run_test("initialize", () => {
|
||||
assert.ok(!default_prevented);
|
||||
|
||||
ev.key = "Enter";
|
||||
search_query_box.is = () => true;
|
||||
$search_query_box.is = () => true;
|
||||
assert.equal(keydown(ev), undefined);
|
||||
assert.ok(default_prevented);
|
||||
|
||||
@@ -206,15 +218,15 @@ run_test("initialize", () => {
|
||||
let operators;
|
||||
let is_blurred;
|
||||
narrow_state.active = () => false;
|
||||
search_query_box.off("blur");
|
||||
search_query_box.on("blur", () => {
|
||||
$search_query_box.off("blur");
|
||||
$search_query_box.on("blur", () => {
|
||||
is_blurred = true;
|
||||
});
|
||||
|
||||
const _setup = (search_box_val) => {
|
||||
is_blurred = false;
|
||||
search_button.prop("disabled", false);
|
||||
search_query_box.val(search_box_val);
|
||||
$search_button.prop("disabled", false);
|
||||
$search_query_box.val(search_box_val);
|
||||
Filter.parse = (search_string) => {
|
||||
assert.equal(search_string, search_box_val);
|
||||
return operators;
|
||||
@@ -235,37 +247,37 @@ run_test("initialize", () => {
|
||||
_setup("");
|
||||
|
||||
ev.key = "a";
|
||||
search_query_box.is = () => false;
|
||||
searchbox_form.trigger(ev);
|
||||
$search_query_box.is = () => false;
|
||||
$searchbox_form.trigger(ev);
|
||||
|
||||
assert.ok(!is_blurred);
|
||||
assert.ok(!search_button.prop("disabled"));
|
||||
assert.ok(!$search_button.prop("disabled"));
|
||||
|
||||
ev.key = "Enter";
|
||||
search_query_box.is = () => false;
|
||||
searchbox_form.trigger(ev);
|
||||
$search_query_box.is = () => false;
|
||||
$searchbox_form.trigger(ev);
|
||||
|
||||
assert.ok(!is_blurred);
|
||||
assert.ok(!search_button.prop("disabled"));
|
||||
assert.ok(!$search_button.prop("disabled"));
|
||||
|
||||
ev.key = "Enter";
|
||||
search_query_box.is = () => true;
|
||||
searchbox_form.trigger(ev);
|
||||
$search_query_box.is = () => true;
|
||||
$searchbox_form.trigger(ev);
|
||||
assert.ok(is_blurred);
|
||||
|
||||
_setup("ver");
|
||||
search.__Rewire__("is_using_input_method", true);
|
||||
searchbox_form.trigger(ev);
|
||||
$searchbox_form.trigger(ev);
|
||||
// No change on Enter keyup event when using input tool
|
||||
assert.ok(!is_blurred);
|
||||
assert.ok(!search_button.prop("disabled"));
|
||||
assert.ok(!$search_button.prop("disabled"));
|
||||
|
||||
_setup("ver");
|
||||
ev.key = "Enter";
|
||||
search_query_box.is = () => true;
|
||||
searchbox_form.trigger(ev);
|
||||
$search_query_box.is = () => true;
|
||||
$searchbox_form.trigger(ev);
|
||||
assert.ok(is_blurred);
|
||||
assert.ok(!search_button.prop("disabled"));
|
||||
assert.ok(!$search_button.prop("disabled"));
|
||||
});
|
||||
|
||||
run_test("initiate_search", () => {
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
const {strict: assert} = require("assert");
|
||||
|
||||
const {mock_esm, zrequire} = require("../zjsunit/namespace");
|
||||
const {mock_esm, with_field, zrequire} = require("../zjsunit/namespace");
|
||||
const {run_test} = require("../zjsunit/test");
|
||||
const {page_params} = require("../zjsunit/zpage_params");
|
||||
|
||||
@@ -93,6 +93,16 @@ test("basic_get_suggestions", ({override_rewire}) => {
|
||||
assert.deepEqual(suggestions.strings, expected);
|
||||
});
|
||||
|
||||
test("basic_get_suggestions_for_spectator", ({override_rewire}) => {
|
||||
override_rewire(stream_data, "subscribed_streams", () => []);
|
||||
page_params.is_spectator = true;
|
||||
|
||||
const query = "";
|
||||
const suggestions = get_suggestions("", query);
|
||||
assert.deepEqual(suggestions.strings, ["", "has:link", "has:image", "has:attachment"]);
|
||||
page_params.is_spectator = false;
|
||||
});
|
||||
|
||||
test("subset_suggestions", () => {
|
||||
const query = "stream:Denmark topic:Hamlet shakespeare";
|
||||
|
||||
@@ -709,6 +719,49 @@ test("topic_suggestions", ({override, override_rewire}) => {
|
||||
assert.deepEqual(suggestions.strings, expected);
|
||||
});
|
||||
|
||||
test("topic_suggestions (limits)", () => {
|
||||
let candidate_topics = [];
|
||||
|
||||
function assert_result(guess, expected_topics) {
|
||||
assert.deepEqual(
|
||||
search.get_topic_suggestions_from_candidates({candidate_topics, guess}),
|
||||
expected_topics,
|
||||
);
|
||||
}
|
||||
|
||||
assert_result("", []);
|
||||
assert_result("zzz", []);
|
||||
|
||||
candidate_topics = ["a", "b", "c"];
|
||||
assert_result("", ["a", "b", "c"]);
|
||||
assert_result("b", ["b"]);
|
||||
assert_result("z", []);
|
||||
|
||||
candidate_topics = [
|
||||
"a1",
|
||||
"a2",
|
||||
"b1",
|
||||
"b2",
|
||||
"a3",
|
||||
"a4",
|
||||
"a5",
|
||||
"c1",
|
||||
"a6",
|
||||
"a7",
|
||||
"a8",
|
||||
"c2",
|
||||
"a9",
|
||||
"a10",
|
||||
"a11",
|
||||
"a12",
|
||||
];
|
||||
// We max out at 10 topics, so as not to overwhelm the user.
|
||||
assert_result("", ["a1", "a2", "b1", "b2", "a3", "a4", "a5", "c1", "a6", "a7"]);
|
||||
assert_result("a", ["a1", "a2", "a3", "a4", "a5", "a6", "a7", "a8", "a9", "a10"]);
|
||||
assert_result("b", ["b1", "b2"]);
|
||||
assert_result("z", []);
|
||||
});
|
||||
|
||||
test("whitespace_glitch", ({override_rewire}) => {
|
||||
const query = "stream:office "; // note trailing space
|
||||
|
||||
@@ -877,3 +930,58 @@ test("queries_with_spaces", ({override_rewire}) => {
|
||||
expected = ["stream:offi", "stream:office"];
|
||||
assert.deepEqual(suggestions.strings, expected);
|
||||
});
|
||||
|
||||
function people_suggestion_setup() {
|
||||
const ted = {
|
||||
email: "ted@zulip.com",
|
||||
user_id: 201,
|
||||
full_name: "Ted Smith",
|
||||
};
|
||||
people.add_active_user(ted);
|
||||
|
||||
const bob = {
|
||||
email: "bob@zulip.com",
|
||||
user_id: 202,
|
||||
full_name: "Bob Térry",
|
||||
};
|
||||
|
||||
people.add_active_user(bob);
|
||||
const alice = {
|
||||
email: "alice@zulip.com",
|
||||
user_id: 203,
|
||||
full_name: "Alice Ignore",
|
||||
};
|
||||
people.add_active_user(alice);
|
||||
}
|
||||
|
||||
test("people_suggestion (Admin only email visibility)", ({override_rewire}) => {
|
||||
/* Suggestions when realm_email_address_visibility is set to admin
|
||||
only */
|
||||
override_rewire(narrow_state, "stream", () => {});
|
||||
people_suggestion_setup();
|
||||
|
||||
const query = "te";
|
||||
const suggestions = with_field(page_params, "is_admin", false, () =>
|
||||
get_suggestions("", query),
|
||||
);
|
||||
|
||||
const expected = [
|
||||
"te",
|
||||
"sender:bob@zulip.com",
|
||||
"sender:ted@zulip.com",
|
||||
"pm-with:bob@zulip.com", // bob térry
|
||||
"pm-with:ted@zulip.com",
|
||||
"group-pm-with:bob@zulip.com",
|
||||
"group-pm-with:ted@zulip.com",
|
||||
];
|
||||
|
||||
assert.deepEqual(suggestions.strings, expected);
|
||||
|
||||
const describe = (q) => suggestions.lookup_table.get(q).description;
|
||||
|
||||
assert.equal(
|
||||
describe("pm-with:ted@zulip.com"),
|
||||
"Private messages with <strong>Te</strong>d Smith",
|
||||
);
|
||||
assert.equal(describe("sender:ted@zulip.com"), "Sent by <strong>Te</strong>d Smith");
|
||||
});
|
||||
@@ -91,32 +91,32 @@ test("generate_botserverrc_content", () => {
|
||||
});
|
||||
|
||||
function test_create_bot_type_input_box_toggle(f) {
|
||||
const create_payload_url = $("#create_payload_url");
|
||||
const payload_url_inputbox = $("#payload_url_inputbox");
|
||||
const config_inputbox = $("#config_inputbox");
|
||||
const $create_payload_url = $("#create_payload_url");
|
||||
const $payload_url_inputbox = $("#payload_url_inputbox");
|
||||
const $config_inputbox = $("#config_inputbox");
|
||||
const EMBEDDED_BOT_TYPE = "4";
|
||||
const OUTGOING_WEBHOOK_BOT_TYPE = "3";
|
||||
const GENERIC_BOT_TYPE = "1";
|
||||
|
||||
$("#create_bot_type :selected").val(EMBEDDED_BOT_TYPE);
|
||||
f();
|
||||
assert.ok(!create_payload_url.hasClass("required"));
|
||||
assert.ok(!payload_url_inputbox.visible());
|
||||
assert.ok(!$create_payload_url.hasClass("required"));
|
||||
assert.ok(!$payload_url_inputbox.visible());
|
||||
assert.ok($("#select_service_name").hasClass("required"));
|
||||
assert.ok($("#service_name_list").visible());
|
||||
assert.ok(config_inputbox.visible());
|
||||
assert.ok($config_inputbox.visible());
|
||||
|
||||
$("#create_bot_type :selected").val(OUTGOING_WEBHOOK_BOT_TYPE);
|
||||
f();
|
||||
assert.ok(create_payload_url.hasClass("required"));
|
||||
assert.ok(payload_url_inputbox.visible());
|
||||
assert.ok(!config_inputbox.visible());
|
||||
assert.ok($create_payload_url.hasClass("required"));
|
||||
assert.ok($payload_url_inputbox.visible());
|
||||
assert.ok(!$config_inputbox.visible());
|
||||
|
||||
$("#create_bot_type :selected").val(GENERIC_BOT_TYPE);
|
||||
f();
|
||||
assert.ok(!create_payload_url.hasClass("required"));
|
||||
assert.ok(!payload_url_inputbox.visible());
|
||||
assert.ok(!config_inputbox.visible());
|
||||
assert.ok(!$create_payload_url.hasClass("required"));
|
||||
assert.ok(!$payload_url_inputbox.visible());
|
||||
assert.ok(!$config_inputbox.visible());
|
||||
}
|
||||
|
||||
test("test tab clicks", ({override}) => {
|
||||
@@ -125,10 +125,10 @@ test("test tab clicks", ({override}) => {
|
||||
$("#create_bot_form").validate = () => {};
|
||||
|
||||
$("#config_inputbox").children = () => {
|
||||
const mock_children = {
|
||||
const $mock_children = {
|
||||
hide: () => {},
|
||||
};
|
||||
return mock_children;
|
||||
return $mock_children;
|
||||
};
|
||||
|
||||
override(avatar, "build_bot_create_widget", () => {});
|
||||
@@ -137,55 +137,55 @@ test("test tab clicks", ({override}) => {
|
||||
|
||||
test_create_bot_type_input_box_toggle(() => $("#create_bot_type").trigger("change"));
|
||||
|
||||
function click_on_tab(tab_elem) {
|
||||
tab_elem.trigger("click");
|
||||
function click_on_tab($tab_elem) {
|
||||
$tab_elem.trigger("click");
|
||||
}
|
||||
|
||||
const tabs = {
|
||||
add: $("#bots_lists_navbar .add-a-new-bot-tab"),
|
||||
active: $("#bots_lists_navbar .active-bots-tab"),
|
||||
inactive: $("#bots_lists_navbar .inactive-bots-tab"),
|
||||
$add: $("#bots_lists_navbar .add-a-new-bot-tab"),
|
||||
$active: $("#bots_lists_navbar .active-bots-tab"),
|
||||
$inactive: $("#bots_lists_navbar .inactive-bots-tab"),
|
||||
};
|
||||
|
||||
$("#bots_lists_navbar .active").removeClass = (cls) => {
|
||||
assert.equal(cls, "active");
|
||||
for (const tab of Object.values(tabs)) {
|
||||
tab.removeClass("active");
|
||||
for (const $tab of Object.values(tabs)) {
|
||||
$tab.removeClass("active");
|
||||
}
|
||||
};
|
||||
|
||||
const forms = {
|
||||
add: $("#add-a-new-bot-form"),
|
||||
active: $("#active_bots_list"),
|
||||
inactive: $("#inactive_bots_list"),
|
||||
$add: $("#add-a-new-bot-form"),
|
||||
$active: $("#active_bots_list"),
|
||||
$inactive: $("#inactive_bots_list"),
|
||||
};
|
||||
|
||||
click_on_tab(tabs.add);
|
||||
assert.ok(tabs.add.hasClass("active"));
|
||||
assert.ok(!tabs.active.hasClass("active"));
|
||||
assert.ok(!tabs.inactive.hasClass("active"));
|
||||
click_on_tab(tabs.$add);
|
||||
assert.ok(tabs.$add.hasClass("active"));
|
||||
assert.ok(!tabs.$active.hasClass("active"));
|
||||
assert.ok(!tabs.$inactive.hasClass("active"));
|
||||
|
||||
assert.ok(forms.add.visible());
|
||||
assert.ok(!forms.active.visible());
|
||||
assert.ok(!forms.inactive.visible());
|
||||
assert.ok(forms.$add.visible());
|
||||
assert.ok(!forms.$active.visible());
|
||||
assert.ok(!forms.$inactive.visible());
|
||||
|
||||
click_on_tab(tabs.active);
|
||||
assert.ok(!tabs.add.hasClass("active"));
|
||||
assert.ok(tabs.active.hasClass("active"));
|
||||
assert.ok(!tabs.inactive.hasClass("active"));
|
||||
click_on_tab(tabs.$active);
|
||||
assert.ok(!tabs.$add.hasClass("active"));
|
||||
assert.ok(tabs.$active.hasClass("active"));
|
||||
assert.ok(!tabs.$inactive.hasClass("active"));
|
||||
|
||||
assert.ok(!forms.add.visible());
|
||||
assert.ok(forms.active.visible());
|
||||
assert.ok(!forms.inactive.visible());
|
||||
assert.ok(!forms.$add.visible());
|
||||
assert.ok(forms.$active.visible());
|
||||
assert.ok(!forms.$inactive.visible());
|
||||
|
||||
click_on_tab(tabs.inactive);
|
||||
assert.ok(!tabs.add.hasClass("active"));
|
||||
assert.ok(!tabs.active.hasClass("active"));
|
||||
assert.ok(tabs.inactive.hasClass("active"));
|
||||
click_on_tab(tabs.$inactive);
|
||||
assert.ok(!tabs.$add.hasClass("active"));
|
||||
assert.ok(!tabs.$active.hasClass("active"));
|
||||
assert.ok(tabs.$inactive.hasClass("active"));
|
||||
|
||||
assert.ok(!forms.add.visible());
|
||||
assert.ok(!forms.active.visible());
|
||||
assert.ok(forms.inactive.visible());
|
||||
assert.ok(!forms.$add.visible());
|
||||
assert.ok(!forms.$active.visible());
|
||||
assert.ok(forms.$inactive.visible());
|
||||
});
|
||||
|
||||
test("can_create_new_bots", () => {
|
||||
|
||||
@@ -51,15 +51,15 @@ run_test("settings", ({override_rewire}) => {
|
||||
stopPropagation: noop,
|
||||
};
|
||||
|
||||
const topic_fake_this = $.create("fake.settings-unmute-topic");
|
||||
const topic_tr_html = $('tr[data-topic="js"]');
|
||||
topic_fake_this.closest = (opts) => {
|
||||
const $topic_fake_this = $.create("fake.settings-unmute-topic");
|
||||
const $topic_tr_html = $('tr[data-topic="js"]');
|
||||
$topic_fake_this.closest = (opts) => {
|
||||
assert.equal(opts, "tr");
|
||||
return topic_tr_html;
|
||||
return $topic_tr_html;
|
||||
};
|
||||
|
||||
let topic_data_called = 0;
|
||||
topic_tr_html.attr = (opts) => {
|
||||
$topic_tr_html.attr = (opts) => {
|
||||
if (opts === "data-stream-id") {
|
||||
topic_data_called += 1;
|
||||
return frontend.stream_id;
|
||||
@@ -77,7 +77,7 @@ run_test("settings", ({override_rewire}) => {
|
||||
assert.equal(topic, "js");
|
||||
unmute_topic_called = true;
|
||||
};
|
||||
topic_click_handler.call(topic_fake_this, event);
|
||||
topic_click_handler.call($topic_fake_this, event);
|
||||
assert.ok(unmute_topic_called);
|
||||
assert.equal(topic_data_called, 2);
|
||||
});
|
||||
|
||||
@@ -42,15 +42,15 @@ run_test("settings", ({override_rewire}) => {
|
||||
stopPropagation: noop,
|
||||
};
|
||||
|
||||
const unmute_button = $.create("settings-unmute-user");
|
||||
const fake_row = $('tr[data-user-id="5"]');
|
||||
unmute_button.closest = (opts) => {
|
||||
const $unmute_button = $.create("settings-unmute-user");
|
||||
const $fake_row = $('tr[data-user-id="5"]');
|
||||
$unmute_button.closest = (opts) => {
|
||||
assert.equal(opts, "tr");
|
||||
return fake_row;
|
||||
return $fake_row;
|
||||
};
|
||||
|
||||
let row_attribute_fetched = false;
|
||||
fake_row.attr = (opts) => {
|
||||
$fake_row.attr = (opts) => {
|
||||
if (opts === "data-user-id") {
|
||||
row_attribute_fetched += 1;
|
||||
return "5";
|
||||
@@ -64,7 +64,7 @@ run_test("settings", ({override_rewire}) => {
|
||||
unmute_user_called = true;
|
||||
};
|
||||
|
||||
unmute_click_handler.call(unmute_button, event);
|
||||
unmute_click_handler.call($unmute_button, event);
|
||||
assert.ok(unmute_user_called);
|
||||
assert.ok(row_attribute_fetched);
|
||||
});
|
||||
|
||||
@@ -31,12 +31,12 @@ mock_esm("../../static/js/loading", {
|
||||
destroy_indicator: noop,
|
||||
});
|
||||
mock_esm("../../static/js/ui_report", {
|
||||
success(msg, elem) {
|
||||
elem.val(msg);
|
||||
success(msg, $elem) {
|
||||
$elem.val(msg);
|
||||
},
|
||||
|
||||
error(msg, xhr, elem) {
|
||||
elem.val(msg);
|
||||
error(msg, xhr, $elem) {
|
||||
$elem.val(msg);
|
||||
},
|
||||
});
|
||||
|
||||
@@ -74,9 +74,9 @@ test("unloaded", () => {
|
||||
});
|
||||
|
||||
function simulate_realm_domains_table() {
|
||||
const tr_stub = $.create("realm-tr-stub");
|
||||
$("#realm_domains_table tbody").set_find_results("tr", tr_stub);
|
||||
tr_stub.remove = () => {};
|
||||
const $tr_stub = $.create("realm-tr-stub");
|
||||
$("#realm_domains_table tbody").set_find_results("tr", $tr_stub);
|
||||
$tr_stub.remove = () => {};
|
||||
|
||||
let appended;
|
||||
$("#realm_domains_table tbody").append = (html) => {
|
||||
@@ -90,7 +90,7 @@ function simulate_realm_domains_table() {
|
||||
}
|
||||
|
||||
function test_realms_domain_modal(override, add_realm_domain) {
|
||||
const info = $(".realm_domains_info");
|
||||
const $info = $(".realm_domains_info");
|
||||
|
||||
$("#add-realm-domain-widget").set_find_results(
|
||||
".new-realm-domain",
|
||||
@@ -117,46 +117,46 @@ function test_realms_domain_modal(override, add_realm_domain) {
|
||||
assert.ok(posted);
|
||||
|
||||
success_callback();
|
||||
assert.equal(info.val(), "translated HTML: Added successfully!");
|
||||
assert.equal($info.val(), "translated HTML: Added successfully!");
|
||||
|
||||
error_callback({});
|
||||
assert.equal(info.val(), "translated HTML: Failed");
|
||||
assert.equal($info.val(), "translated HTML: Failed");
|
||||
}
|
||||
|
||||
function createSaveButtons(subsection) {
|
||||
const stub_save_button_header = $(`#org-${CSS.escape(subsection)}`);
|
||||
const save_button_controls = $(".save-button-controls");
|
||||
const stub_save_button = $(`#org-submit-${CSS.escape(subsection)}`);
|
||||
const stub_discard_button = $(`#org-discard-${CSS.escape(subsection)}`);
|
||||
const stub_save_button_text = $(".save-discard-widget-button-text");
|
||||
stub_save_button_header.set_find_results(
|
||||
const $stub_save_button_header = $(`#org-${CSS.escape(subsection)}`);
|
||||
const $save_button_controls = $(".save-button-controls");
|
||||
const $stub_save_button = $(`#org-submit-${CSS.escape(subsection)}`);
|
||||
const $stub_discard_button = $(`#org-discard-${CSS.escape(subsection)}`);
|
||||
const $stub_save_button_text = $(".save-discard-widget-button-text");
|
||||
$stub_save_button_header.set_find_results(
|
||||
".subsection-failed-status p",
|
||||
$("<failed status element>"),
|
||||
$("<failed-status-stub>"),
|
||||
);
|
||||
stub_save_button.closest = () => stub_save_button_header;
|
||||
save_button_controls.set_find_results(".save-button", stub_save_button);
|
||||
stub_save_button.set_find_results(".save-discard-widget-button-text", stub_save_button_text);
|
||||
stub_save_button_header.set_find_results(".save-button-controls", save_button_controls);
|
||||
stub_save_button_header.set_find_results(
|
||||
$stub_save_button.closest = () => $stub_save_button_header;
|
||||
$save_button_controls.set_find_results(".save-button", $stub_save_button);
|
||||
$stub_save_button.set_find_results(".save-discard-widget-button-text", $stub_save_button_text);
|
||||
$stub_save_button_header.set_find_results(".save-button-controls", $save_button_controls);
|
||||
$stub_save_button_header.set_find_results(
|
||||
".subsection-changes-discard button",
|
||||
$(`#org-discard-${CSS.escape(subsection)}`),
|
||||
);
|
||||
save_button_controls.set_find_results(".discard-button", stub_discard_button);
|
||||
$save_button_controls.set_find_results(".discard-button", $stub_discard_button);
|
||||
const props = {};
|
||||
props.hidden = false;
|
||||
save_button_controls.fadeIn = () => {
|
||||
$save_button_controls.fadeIn = () => {
|
||||
props.hidden = false;
|
||||
};
|
||||
save_button_controls.fadeOut = () => {
|
||||
$save_button_controls.fadeOut = () => {
|
||||
props.hidden = true;
|
||||
};
|
||||
return {
|
||||
props,
|
||||
save_button: stub_save_button,
|
||||
discard_button: stub_discard_button,
|
||||
save_button_header: stub_save_button_header,
|
||||
save_button_controls,
|
||||
save_button_text: stub_save_button_text,
|
||||
$save_button: $stub_save_button,
|
||||
$discard_button: $stub_discard_button,
|
||||
$save_button_header: $stub_save_button_header,
|
||||
$save_button_controls,
|
||||
$save_button_text: $stub_save_button_text,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -193,55 +193,55 @@ function test_submit_settings_form(override, submit_form) {
|
||||
let subsection = "other-permissions";
|
||||
ev.currentTarget = `#org-submit-${CSS.escape(subsection)}`;
|
||||
let stubs = createSaveButtons(subsection);
|
||||
let save_button = stubs.save_button;
|
||||
save_button.attr("id", `org-submit-${subsection}`);
|
||||
save_button.replace = () => `${subsection}`;
|
||||
let $save_button = stubs.$save_button;
|
||||
$save_button.attr("id", `org-submit-${subsection}`);
|
||||
$save_button.replace = () => `${subsection}`;
|
||||
|
||||
$("#id_realm_waiting_period_threshold").val(10);
|
||||
|
||||
const invite_to_stream_policy_elem = $("#id_realm_invite_to_stream_policy");
|
||||
invite_to_stream_policy_elem.val("1");
|
||||
invite_to_stream_policy_elem.attr("id", "id_realm_invite_to_stream_policy");
|
||||
invite_to_stream_policy_elem.data = () => "number";
|
||||
const $invite_to_stream_policy_elem = $("#id_realm_invite_to_stream_policy");
|
||||
$invite_to_stream_policy_elem.val("1");
|
||||
$invite_to_stream_policy_elem.attr("id", "id_realm_invite_to_stream_policy");
|
||||
$invite_to_stream_policy_elem.data = () => "number";
|
||||
|
||||
const create_public_stream_policy_elem = $("#id_realm_create_public_stream_policy");
|
||||
create_public_stream_policy_elem.val("2");
|
||||
create_public_stream_policy_elem.attr("id", "id_realm_create_public_stream_policy");
|
||||
create_public_stream_policy_elem.data = () => "number";
|
||||
const $create_public_stream_policy_elem = $("#id_realm_create_public_stream_policy");
|
||||
$create_public_stream_policy_elem.val("2");
|
||||
$create_public_stream_policy_elem.attr("id", "id_realm_create_public_stream_policy");
|
||||
$create_public_stream_policy_elem.data = () => "number";
|
||||
|
||||
const create_private_stream_policy_elem = $("#id_realm_create_private_stream_policy");
|
||||
create_private_stream_policy_elem.val("2");
|
||||
create_private_stream_policy_elem.attr("id", "id_realm_create_private_stream_policy");
|
||||
create_private_stream_policy_elem.data = () => "number";
|
||||
const $create_private_stream_policy_elem = $("#id_realm_create_private_stream_policy");
|
||||
$create_private_stream_policy_elem.val("2");
|
||||
$create_private_stream_policy_elem.attr("id", "id_realm_create_private_stream_policy");
|
||||
$create_private_stream_policy_elem.data = () => "number";
|
||||
|
||||
const add_custom_emoji_policy_elem = $("#id_realm_add_custom_emoji_policy");
|
||||
add_custom_emoji_policy_elem.val("1");
|
||||
add_custom_emoji_policy_elem.attr("id", "id_realm_add_custom_emoji_policy");
|
||||
add_custom_emoji_policy_elem.data = () => "number";
|
||||
const $add_custom_emoji_policy_elem = $("#id_realm_add_custom_emoji_policy");
|
||||
$add_custom_emoji_policy_elem.val("1");
|
||||
$add_custom_emoji_policy_elem.attr("id", "id_realm_add_custom_emoji_policy");
|
||||
$add_custom_emoji_policy_elem.data = () => "number";
|
||||
|
||||
const bot_creation_policy_elem = $("#id_realm_bot_creation_policy");
|
||||
bot_creation_policy_elem.val("1");
|
||||
bot_creation_policy_elem.attr("id", "id_realm_bot_creation_policy");
|
||||
bot_creation_policy_elem.data = () => "number";
|
||||
const email_address_visibility_elem = $("#id_realm_email_address_visibility");
|
||||
email_address_visibility_elem.val("1");
|
||||
email_address_visibility_elem.attr("id", "id_realm_email_address_visibility");
|
||||
email_address_visibility_elem.data = () => "number";
|
||||
const $bot_creation_policy_elem = $("#id_realm_bot_creation_policy");
|
||||
$bot_creation_policy_elem.val("1");
|
||||
$bot_creation_policy_elem.attr("id", "id_realm_bot_creation_policy");
|
||||
$bot_creation_policy_elem.data = () => "number";
|
||||
const $email_address_visibility_elem = $("#id_realm_email_address_visibility");
|
||||
$email_address_visibility_elem.val("1");
|
||||
$email_address_visibility_elem.attr("id", "id_realm_email_address_visibility");
|
||||
$email_address_visibility_elem.data = () => "number";
|
||||
|
||||
const invite_to_realm_policy_elem = $("#id_realm_invite_to_realm_policy");
|
||||
invite_to_realm_policy_elem.val("2");
|
||||
invite_to_realm_policy_elem.attr("id", "id_realm_invite_to_realm_policy");
|
||||
invite_to_realm_policy_elem.data = () => "number";
|
||||
const $invite_to_realm_policy_elem = $("#id_realm_invite_to_realm_policy");
|
||||
$invite_to_realm_policy_elem.val("2");
|
||||
$invite_to_realm_policy_elem.attr("id", "id_realm_invite_to_realm_policy");
|
||||
$invite_to_realm_policy_elem.data = () => "number";
|
||||
|
||||
let subsection_elem = $(`#org-${CSS.escape(subsection)}`);
|
||||
subsection_elem.closest = () => subsection_elem;
|
||||
subsection_elem.set_find_results(".prop-element", [
|
||||
bot_creation_policy_elem,
|
||||
email_address_visibility_elem,
|
||||
add_custom_emoji_policy_elem,
|
||||
create_public_stream_policy_elem,
|
||||
create_private_stream_policy_elem,
|
||||
invite_to_stream_policy_elem,
|
||||
let $subsection_elem = $(`#org-${CSS.escape(subsection)}`);
|
||||
$subsection_elem.closest = () => $subsection_elem;
|
||||
$subsection_elem.set_find_results(".prop-element", [
|
||||
$bot_creation_policy_elem,
|
||||
$email_address_visibility_elem,
|
||||
$add_custom_emoji_policy_elem,
|
||||
$create_public_stream_policy_elem,
|
||||
$create_private_stream_policy_elem,
|
||||
$invite_to_stream_policy_elem,
|
||||
]);
|
||||
|
||||
patched = false;
|
||||
@@ -261,17 +261,17 @@ function test_submit_settings_form(override, submit_form) {
|
||||
subsection = "user-defaults";
|
||||
ev.currentTarget = `#org-submit-${CSS.escape(subsection)}`;
|
||||
stubs = createSaveButtons(subsection);
|
||||
save_button = stubs.save_button;
|
||||
save_button.attr("id", `org-submit-${subsection}`);
|
||||
$save_button = stubs.$save_button;
|
||||
$save_button.attr("id", `org-submit-${subsection}`);
|
||||
|
||||
const realm_default_language_elem = $("#id_realm_default_language");
|
||||
realm_default_language_elem.val("en");
|
||||
realm_default_language_elem.attr("id", "id_realm_default_language");
|
||||
realm_default_language_elem.data = () => "string";
|
||||
const $realm_default_language_elem = $("#id_realm_default_language");
|
||||
$realm_default_language_elem.val("en");
|
||||
$realm_default_language_elem.attr("id", "id_realm_default_language");
|
||||
$realm_default_language_elem.data = () => "string";
|
||||
|
||||
subsection_elem = $(`#org-${CSS.escape(subsection)}`);
|
||||
subsection_elem.closest = () => subsection_elem;
|
||||
subsection_elem.set_find_results(".prop-element", [realm_default_language_elem]);
|
||||
$subsection_elem = $(`#org-${CSS.escape(subsection)}`);
|
||||
$subsection_elem.closest = () => $subsection_elem;
|
||||
$subsection_elem.set_find_results(".prop-element", [$realm_default_language_elem]);
|
||||
|
||||
submit_form(ev);
|
||||
assert.ok(patched);
|
||||
@@ -284,50 +284,50 @@ function test_submit_settings_form(override, submit_form) {
|
||||
// Testing only once for since callback is same for all cases
|
||||
success_callback();
|
||||
assert.equal(stubs.props.hidden, true);
|
||||
assert.equal(save_button.attr("data-status"), "saved");
|
||||
assert.equal(stubs.save_button_text.text(), "translated: Saved");
|
||||
assert.equal($save_button.attr("data-status"), "saved");
|
||||
assert.equal(stubs.$save_button_text.text(), "translated: Saved");
|
||||
}
|
||||
|
||||
function test_change_save_button_state() {
|
||||
const {save_button_controls, save_button_text, save_button, discard_button, props} =
|
||||
const {$save_button_controls, $save_button_text, $save_button, $discard_button, props} =
|
||||
createSaveButtons("msg-editing");
|
||||
save_button.attr("id", "org-submit-msg-editing");
|
||||
$save_button.attr("id", "org-submit-msg-editing");
|
||||
|
||||
{
|
||||
settings_org.change_save_button_state(save_button_controls, "unsaved");
|
||||
assert.equal(save_button_text.text(), "translated: Save changes");
|
||||
settings_org.change_save_button_state($save_button_controls, "unsaved");
|
||||
assert.equal($save_button_text.text(), "translated: Save changes");
|
||||
assert.equal(props.hidden, false);
|
||||
assert.equal(save_button.attr("data-status"), "unsaved");
|
||||
assert.equal(discard_button.visible(), true);
|
||||
assert.equal($save_button.attr("data-status"), "unsaved");
|
||||
assert.equal($discard_button.visible(), true);
|
||||
}
|
||||
{
|
||||
settings_org.change_save_button_state(save_button_controls, "saved");
|
||||
assert.equal(save_button_text.text(), "translated: Save changes");
|
||||
settings_org.change_save_button_state($save_button_controls, "saved");
|
||||
assert.equal($save_button_text.text(), "translated: Save changes");
|
||||
assert.equal(props.hidden, true);
|
||||
assert.equal(save_button.attr("data-status"), "");
|
||||
assert.equal($save_button.attr("data-status"), "");
|
||||
}
|
||||
{
|
||||
settings_org.change_save_button_state(save_button_controls, "saving");
|
||||
assert.equal(save_button_text.text(), "translated: Saving");
|
||||
assert.equal(save_button.attr("data-status"), "saving");
|
||||
assert.equal(save_button.hasClass("saving"), true);
|
||||
assert.equal(discard_button.visible(), false);
|
||||
settings_org.change_save_button_state($save_button_controls, "saving");
|
||||
assert.equal($save_button_text.text(), "translated: Saving");
|
||||
assert.equal($save_button.attr("data-status"), "saving");
|
||||
assert.equal($save_button.hasClass("saving"), true);
|
||||
assert.equal($discard_button.visible(), false);
|
||||
}
|
||||
{
|
||||
settings_org.change_save_button_state(save_button_controls, "discarded");
|
||||
settings_org.change_save_button_state($save_button_controls, "discarded");
|
||||
assert.equal(props.hidden, true);
|
||||
}
|
||||
{
|
||||
settings_org.change_save_button_state(save_button_controls, "succeeded");
|
||||
settings_org.change_save_button_state($save_button_controls, "succeeded");
|
||||
assert.equal(props.hidden, true);
|
||||
assert.equal(save_button.attr("data-status"), "saved");
|
||||
assert.equal(save_button_text.text(), "translated: Saved");
|
||||
assert.equal($save_button.attr("data-status"), "saved");
|
||||
assert.equal($save_button_text.text(), "translated: Saved");
|
||||
}
|
||||
{
|
||||
settings_org.change_save_button_state(save_button_controls, "failed");
|
||||
settings_org.change_save_button_state($save_button_controls, "failed");
|
||||
assert.equal(props.hidden, false);
|
||||
assert.equal(save_button.attr("data-status"), "failed");
|
||||
assert.equal(save_button_text.text(), "translated: Save changes");
|
||||
assert.equal($save_button.attr("data-status"), "failed");
|
||||
assert.equal($save_button_text.text(), "translated: Save changes");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -358,8 +358,8 @@ function test_change_allow_subdomains(change_allow_subdomains) {
|
||||
stopPropagation: noop,
|
||||
};
|
||||
|
||||
const info = $(".realm_domains_info");
|
||||
info.fadeOut = noop;
|
||||
const $info = $(".realm_domains_info");
|
||||
$info.fadeOut = noop;
|
||||
const domain = "example.com";
|
||||
let allow = true;
|
||||
|
||||
@@ -372,33 +372,33 @@ function test_change_allow_subdomains(change_allow_subdomains) {
|
||||
error_callback = req.error;
|
||||
};
|
||||
|
||||
const domain_obj = $.create("domain object");
|
||||
domain_obj.text(domain);
|
||||
const $domain_obj = $.create("domain object");
|
||||
$domain_obj.text(domain);
|
||||
|
||||
const elem_obj = $.create("<elem html>");
|
||||
const parents_obj = $.create("parents object");
|
||||
const $elem_obj = $.create("<elem html>");
|
||||
const $parents_obj = $.create("parents object");
|
||||
|
||||
elem_obj.set_parents_result("tr", parents_obj);
|
||||
parents_obj.set_find_results(".domain", domain_obj);
|
||||
elem_obj.prop("checked", allow);
|
||||
$elem_obj.set_parents_result("tr", $parents_obj);
|
||||
$parents_obj.set_find_results(".domain", $domain_obj);
|
||||
$elem_obj.prop("checked", allow);
|
||||
|
||||
change_allow_subdomains.call(elem_obj, ev);
|
||||
change_allow_subdomains.call($elem_obj, ev);
|
||||
|
||||
success_callback();
|
||||
assert.equal(
|
||||
info.val(),
|
||||
$info.val(),
|
||||
"translated HTML: Update successful: Subdomains allowed for example.com",
|
||||
);
|
||||
|
||||
error_callback({});
|
||||
assert.equal(info.val(), "translated HTML: Failed");
|
||||
assert.equal($info.val(), "translated HTML: Failed");
|
||||
|
||||
allow = false;
|
||||
elem_obj.prop("checked", allow);
|
||||
change_allow_subdomains.call(elem_obj, ev);
|
||||
$elem_obj.prop("checked", allow);
|
||||
change_allow_subdomains.call($elem_obj, ev);
|
||||
success_callback();
|
||||
assert.equal(
|
||||
info.val(),
|
||||
$info.val(),
|
||||
"translated HTML: Update successful: Subdomains no longer allowed for example.com",
|
||||
);
|
||||
}
|
||||
@@ -431,9 +431,9 @@ function test_sync_realm_settings() {
|
||||
|
||||
{
|
||||
/* Test invalid settings property sync */
|
||||
const property_elem = $("#id_realm_invalid_settings_property");
|
||||
property_elem.attr("id", "id_realm_invalid_settings_property");
|
||||
property_elem.length = 1;
|
||||
const $property_elem = $("#id_realm_invalid_settings_property");
|
||||
$property_elem.attr("id", "id_realm_invalid_settings_property");
|
||||
$property_elem.length = 1;
|
||||
|
||||
blueslip.expect(
|
||||
"error",
|
||||
@@ -443,9 +443,9 @@ function test_sync_realm_settings() {
|
||||
}
|
||||
|
||||
function test_common_policy(property_name) {
|
||||
const property_elem = $(`#id_realm_${CSS.escape(property_name)}`);
|
||||
property_elem.length = 1;
|
||||
property_elem.attr("id", `id_realm_${CSS.escape(property_name)}`);
|
||||
const $property_elem = $(`#id_realm_${CSS.escape(property_name)}`);
|
||||
$property_elem.length = 1;
|
||||
$property_elem.attr("id", `id_realm_${CSS.escape(property_name)}`);
|
||||
|
||||
/* Each policy is initialized to 'by_members' and then all the values are tested
|
||||
in the following order - by_admins_only, by_moderators_only, by_full_members,
|
||||
@@ -453,14 +453,14 @@ function test_sync_realm_settings() {
|
||||
|
||||
page_params[`realm_${property_name}`] =
|
||||
settings_config.common_policy_values.by_members.code;
|
||||
property_elem.val(settings_config.common_policy_values.by_members.code);
|
||||
$property_elem.val(settings_config.common_policy_values.by_members.code);
|
||||
|
||||
for (const policy_value of Array.from(
|
||||
Object.values(settings_config.common_policy_values),
|
||||
)) {
|
||||
page_params[`realm_${property_name}`] = policy_value.code;
|
||||
settings_org.sync_realm_settings(property_name);
|
||||
assert.equal(property_elem.val(), policy_value.code);
|
||||
assert.equal($property_elem.val(), policy_value.code);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -471,9 +471,9 @@ function test_sync_realm_settings() {
|
||||
|
||||
{
|
||||
/* Test message content edit limit minutes sync */
|
||||
const property_elem = $("#id_realm_message_content_edit_limit_minutes");
|
||||
property_elem.length = 1;
|
||||
property_elem.attr("id", "id_realm_message_content_edit_limit_minutes");
|
||||
const $property_elem = $("#id_realm_message_content_edit_limit_minutes");
|
||||
$property_elem.length = 1;
|
||||
$property_elem.attr("id", "id_realm_message_content_edit_limit_minutes");
|
||||
|
||||
page_params.realm_create_public_stream_policy = 1;
|
||||
page_params.realm_message_content_edit_limit_seconds = 120;
|
||||
@@ -484,9 +484,9 @@ function test_sync_realm_settings() {
|
||||
|
||||
{
|
||||
/* Test message content edit limit dropdown value sync */
|
||||
const property_elem = $("#id_realm_msg_edit_limit_setting");
|
||||
property_elem.length = 1;
|
||||
property_elem.attr("id", "id_realm_msg_edit_limit_setting");
|
||||
const $property_elem = $("#id_realm_msg_edit_limit_setting");
|
||||
$property_elem.length = 1;
|
||||
$property_elem.attr("id", "id_realm_msg_edit_limit_setting");
|
||||
|
||||
page_params.realm_allow_message_editing = false;
|
||||
page_params.realm_message_content_edit_limit_seconds = 120;
|
||||
@@ -506,9 +506,9 @@ function test_sync_realm_settings() {
|
||||
|
||||
{
|
||||
/* Test message content edit limit minutes sync */
|
||||
const property_elem = $("#id_realm_message_content_edit_limit_minutes");
|
||||
property_elem.length = 1;
|
||||
property_elem.attr("id", "id_realm_message_content_edit_limit_minutes");
|
||||
const $property_elem = $("#id_realm_message_content_edit_limit_minutes");
|
||||
$property_elem.length = 1;
|
||||
$property_elem.attr("id", "id_realm_message_content_edit_limit_minutes");
|
||||
|
||||
page_params.realm_create_public_stream_policy = 1;
|
||||
page_params.realm_message_content_edit_limit_seconds = 120;
|
||||
@@ -519,9 +519,9 @@ function test_sync_realm_settings() {
|
||||
|
||||
{
|
||||
/* Test organization joining restrictions settings sync */
|
||||
const property_elem = $("#id_realm_org_join_restrictions");
|
||||
property_elem.length = 1;
|
||||
property_elem.attr("id", "id_realm_org_join_restrictions");
|
||||
const $property_elem = $("#id_realm_org_join_restrictions");
|
||||
$property_elem.length = 1;
|
||||
$property_elem.attr("id", "id_realm_org_join_restrictions");
|
||||
|
||||
page_params.realm_emails_restricted_to_domains = true;
|
||||
page_params.realm_disallow_disposable_email_addresses = false;
|
||||
@@ -541,10 +541,10 @@ function test_sync_realm_settings() {
|
||||
}
|
||||
|
||||
function test_parse_time_limit() {
|
||||
const elem = $("#id_realm_message_content_edit_limit_minutes");
|
||||
const $elem = $("#id_realm_message_content_edit_limit_minutes");
|
||||
const test_function = (value, expected_value = value) => {
|
||||
elem.val(value);
|
||||
page_params.realm_message_content_edit_limit_seconds = settings_org.parse_time_limit(elem);
|
||||
$elem.val(value);
|
||||
page_params.realm_message_content_edit_limit_seconds = settings_org.parse_time_limit($elem);
|
||||
assert.equal(
|
||||
settings_org.get_realm_time_limits_in_minutes(
|
||||
"realm_message_content_edit_limit_seconds",
|
||||
@@ -587,40 +587,40 @@ function test_discard_changes_button(discard_changes) {
|
||||
settings_config.common_message_policy_values.by_everyone.code;
|
||||
page_params.realm_message_content_delete_limit_seconds = 120;
|
||||
|
||||
const allow_edit_history = $("#id_realm_allow_edit_history").prop("checked", false);
|
||||
const edit_topic_policy = $("#id_realm_edit_topic_policy").val(
|
||||
const $allow_edit_history = $("#id_realm_allow_edit_history").prop("checked", false);
|
||||
const $edit_topic_policy = $("#id_realm_edit_topic_policy").val(
|
||||
settings_config.common_message_policy_values.by_admins_only.code,
|
||||
);
|
||||
const msg_edit_limit_setting = $("#id_realm_msg_edit_limit_setting").val("custom_limit");
|
||||
const message_content_edit_limit_minutes = $(
|
||||
const $msg_edit_limit_setting = $("#id_realm_msg_edit_limit_setting").val("custom_limit");
|
||||
const $message_content_edit_limit_minutes = $(
|
||||
"#id_realm_message_content_edit_limit_minutes",
|
||||
).val(130);
|
||||
const msg_delete_limit_setting = $("#id_realm_msg_delete_limit_setting").val("custom_limit");
|
||||
const message_content_delete_limit_minutes = $(
|
||||
const $msg_delete_limit_setting = $("#id_realm_msg_delete_limit_setting").val("custom_limit");
|
||||
const $message_content_delete_limit_minutes = $(
|
||||
"#id_realm_message_content_delete_limit_minutes",
|
||||
).val(130);
|
||||
|
||||
allow_edit_history.attr("id", "id_realm_allow_edit_history");
|
||||
msg_edit_limit_setting.attr("id", "id_realm_msg_edit_limit_setting");
|
||||
msg_delete_limit_setting.attr("id", "id_realm_msg_delete_limit_setting");
|
||||
edit_topic_policy.attr("id", "id_realm_edit_topic_policy");
|
||||
message_content_edit_limit_minutes.attr("id", "id_realm_message_content_edit_limit_minutes");
|
||||
message_content_delete_limit_minutes.attr(
|
||||
$allow_edit_history.attr("id", "id_realm_allow_edit_history");
|
||||
$msg_edit_limit_setting.attr("id", "id_realm_msg_edit_limit_setting");
|
||||
$msg_delete_limit_setting.attr("id", "id_realm_msg_delete_limit_setting");
|
||||
$edit_topic_policy.attr("id", "id_realm_edit_topic_policy");
|
||||
$message_content_edit_limit_minutes.attr("id", "id_realm_message_content_edit_limit_minutes");
|
||||
$message_content_delete_limit_minutes.attr(
|
||||
"id",
|
||||
"id_realm_message_content_delete_limit_minutes",
|
||||
);
|
||||
|
||||
const discard_button_parent = $(".org-subsection-parent");
|
||||
discard_button_parent.find = () => [
|
||||
allow_edit_history,
|
||||
msg_edit_limit_setting,
|
||||
msg_delete_limit_setting,
|
||||
edit_topic_policy,
|
||||
message_content_edit_limit_minutes,
|
||||
message_content_delete_limit_minutes,
|
||||
const $discard_button_parent = $(".org-subsection-parent");
|
||||
$discard_button_parent.find = () => [
|
||||
$allow_edit_history,
|
||||
$msg_edit_limit_setting,
|
||||
$msg_delete_limit_setting,
|
||||
$edit_topic_policy,
|
||||
$message_content_edit_limit_minutes,
|
||||
$message_content_delete_limit_minutes,
|
||||
];
|
||||
|
||||
$("#org-discard-msg-editing").closest = () => discard_button_parent;
|
||||
$("#org-discard-msg-editing").closest = () => $discard_button_parent;
|
||||
|
||||
const stubbed_function = settings_org.change_save_button_state;
|
||||
settings_org.__Rewire__("change_save_button_state", (save_button_controls, state) => {
|
||||
@@ -629,15 +629,15 @@ function test_discard_changes_button(discard_changes) {
|
||||
|
||||
discard_changes(ev);
|
||||
|
||||
assert.equal(allow_edit_history.prop("checked"), true);
|
||||
assert.equal($allow_edit_history.prop("checked"), true);
|
||||
assert.equal(
|
||||
edit_topic_policy.val(),
|
||||
$edit_topic_policy.val(),
|
||||
settings_config.common_message_policy_values.by_everyone.code,
|
||||
);
|
||||
assert.equal(msg_edit_limit_setting.val(), "upto_one_hour");
|
||||
assert.equal(message_content_edit_limit_minutes.val(), "60");
|
||||
assert.equal(msg_delete_limit_setting.val(), "upto_two_min");
|
||||
assert.equal(message_content_delete_limit_minutes.val(), "2");
|
||||
assert.equal($msg_edit_limit_setting.val(), "upto_one_hour");
|
||||
assert.equal($message_content_edit_limit_minutes.val(), "60");
|
||||
assert.equal($msg_delete_limit_setting.val(), "upto_two_min");
|
||||
assert.equal($message_content_delete_limit_minutes.val(), "2");
|
||||
|
||||
settings_org.__Rewire__("change_save_button_state", stubbed_function);
|
||||
}
|
||||
@@ -683,8 +683,8 @@ test("set_up", ({override, override_rewire, mock_template}) => {
|
||||
$("#enable_digest_emails_label").set_parent($.create("<stub digest setting checkbox>"));
|
||||
$("#id_realm_digest_weekday").set_parent($.create("<stub digest weekday setting dropdown>"));
|
||||
$("#allowed_domains_label").set_parent($.create("<stub-allowed-domain-label-parent>"));
|
||||
const waiting_period_parent_elem = $.create("waiting-period-parent-stub");
|
||||
$("#id_realm_waiting_period_threshold").set_parent(waiting_period_parent_elem);
|
||||
const $waiting_period_parent_elem = $.create("waiting-period-parent-stub");
|
||||
$("#id_realm_waiting_period_threshold").set_parent($waiting_period_parent_elem);
|
||||
$("#id_realm_create_web_public_stream_policy").set_parent(
|
||||
$.create("<stub-create-web-public-stream-policy-parent>"),
|
||||
);
|
||||
@@ -829,8 +829,8 @@ test("test get_sorted_options_list", () => {
|
||||
test("misc", ({override_rewire}) => {
|
||||
page_params.is_admin = false;
|
||||
|
||||
const stub_notification_disable_parent = $.create("<stub notification_disable parent");
|
||||
stub_notification_disable_parent.set_find_results(
|
||||
const $stub_notification_disable_parent = $.create("<stub notification_disable parent");
|
||||
$stub_notification_disable_parent.set_find_results(
|
||||
".dropdown_list_reset_button",
|
||||
$.create("<disable link>"),
|
||||
);
|
||||
@@ -904,14 +904,14 @@ test("misc", ({override_rewire}) => {
|
||||
"realm_signup_notifications_stream_id",
|
||||
"realm_default_code_block_language",
|
||||
];
|
||||
const dropdown_list_parent = $.create("<list parent>");
|
||||
dropdown_list_parent.set_find_results(
|
||||
const $dropdown_list_parent = $.create("<list parent>");
|
||||
$dropdown_list_parent.set_find_results(
|
||||
".dropdown_list_reset_button",
|
||||
$.create("<disable button>"),
|
||||
);
|
||||
for (const name of widget_settings) {
|
||||
const elem = $.create(`#${CSS.escape(name)}_widget #${CSS.escape(name)}_name`);
|
||||
elem.closest = () => dropdown_list_parent;
|
||||
const $elem = $.create(`#${CSS.escape(name)}_widget #${CSS.escape(name)}_name`);
|
||||
$elem.closest = () => $dropdown_list_parent;
|
||||
}
|
||||
|
||||
// We do not define any settings we need in page_params yet, but we don't need to for this test.
|
||||
@@ -923,32 +923,32 @@ test("misc", ({override_rewire}) => {
|
||||
settings_org.init_dropdown_widgets();
|
||||
|
||||
let setting_name = "realm_notifications_stream_id";
|
||||
let elem = $(`#${CSS.escape(setting_name)}_widget #${CSS.escape(setting_name)}_name`);
|
||||
elem.closest = () => stub_notification_disable_parent;
|
||||
let $elem = $(`#${CSS.escape(setting_name)}_widget #${CSS.escape(setting_name)}_name`);
|
||||
$elem.closest = () => $stub_notification_disable_parent;
|
||||
sub_store.__Rewire__("get", (stream_id) => {
|
||||
assert.equal(stream_id, 42);
|
||||
return {name: "some_stream"};
|
||||
});
|
||||
settings_org.notifications_stream_widget.render(42);
|
||||
assert.equal(elem.text(), "#some_stream");
|
||||
assert.ok(!elem.hasClass("text-warning"));
|
||||
assert.equal($elem.text(), "#some_stream");
|
||||
assert.ok(!$elem.hasClass("text-warning"));
|
||||
|
||||
settings_org.notifications_stream_widget.render(undefined);
|
||||
assert.equal(elem.text(), "translated: Disabled");
|
||||
assert.ok(elem.hasClass("text-warning"));
|
||||
assert.equal($elem.text(), "translated: Disabled");
|
||||
assert.ok($elem.hasClass("text-warning"));
|
||||
|
||||
setting_name = "realm_signup_notifications_stream_id";
|
||||
elem = $(`#${CSS.escape(setting_name)}_widget #${CSS.escape(setting_name)}_name`);
|
||||
elem.closest = () => stub_notification_disable_parent;
|
||||
$elem = $(`#${CSS.escape(setting_name)}_widget #${CSS.escape(setting_name)}_name`);
|
||||
$elem.closest = () => $stub_notification_disable_parent;
|
||||
sub_store.__Rewire__("get", (stream_id) => {
|
||||
assert.equal(stream_id, 75);
|
||||
return {name: "some_stream"};
|
||||
});
|
||||
settings_org.signup_notifications_stream_widget.render(75);
|
||||
assert.equal(elem.text(), "#some_stream");
|
||||
assert.ok(!elem.hasClass("text-warning"));
|
||||
assert.equal($elem.text(), "#some_stream");
|
||||
assert.ok(!$elem.hasClass("text-warning"));
|
||||
|
||||
settings_org.signup_notifications_stream_widget.render(undefined);
|
||||
assert.equal(elem.text(), "translated: Disabled");
|
||||
assert.ok(elem.hasClass("text-warning"));
|
||||
assert.equal($elem.text(), "translated: Disabled");
|
||||
assert.ok($elem.hasClass("text-warning"));
|
||||
});
|
||||
|
||||
@@ -43,19 +43,19 @@ function test_populate(opts, template_data) {
|
||||
const fields_data = opts.fields_data;
|
||||
|
||||
page_params.is_admin = opts.is_admin;
|
||||
const table = $("#admin_profile_fields_table");
|
||||
const rows = $.create("rows");
|
||||
const form = $.create("forms");
|
||||
table.set_find_results("tr.profile-field-row", rows);
|
||||
table.set_find_results("tr.profile-field-form", form);
|
||||
const $table = $("#admin_profile_fields_table");
|
||||
const $rows = $.create("rows");
|
||||
const $form = $.create("forms");
|
||||
$table.set_find_results("tr.profile-field-row", $rows);
|
||||
$table.set_find_results("tr.profile-field-form", $form);
|
||||
|
||||
table[0] = "stub";
|
||||
$table[0] = "stub";
|
||||
|
||||
rows.remove = () => {};
|
||||
form.remove = () => {};
|
||||
$rows.remove = () => {};
|
||||
$form.remove = () => {};
|
||||
|
||||
let num_appends = 0;
|
||||
table.append = () => {
|
||||
$table.append = () => {
|
||||
num_appends += 1;
|
||||
};
|
||||
|
||||
|
||||
@@ -34,9 +34,9 @@ const settings_data = zrequire("settings_data");
|
||||
const settings_user_groups = zrequire("settings_user_groups");
|
||||
const user_pill = zrequire("user_pill");
|
||||
|
||||
function reset_test_setup(pill_container_stub) {
|
||||
function reset_test_setup($pill_container_stub) {
|
||||
function input_pill_stub(opts) {
|
||||
assert.equal(opts.container, pill_container_stub);
|
||||
assert.equal(opts.$container, $pill_container_stub);
|
||||
create_item_handler = opts.create_item_from_text;
|
||||
assert.ok(create_item_handler);
|
||||
return pills;
|
||||
@@ -119,18 +119,18 @@ test_ui("populate_user_groups", ({override_rewire, mock_template}) => {
|
||||
people.get_visible_email = () => bob.email;
|
||||
|
||||
let templates_render_called = false;
|
||||
const fake_rendered_temp = $.create("fake_admin_user_group_list_template_rendered");
|
||||
const $fake_rendered_temp = $.create("fake_admin_user_group_list_template_rendered");
|
||||
mock_template("settings/admin_user_group_list.hbs", false, (args) => {
|
||||
assert.equal(args.user_group.id, 1);
|
||||
assert.equal(args.user_group.name, "Mobile");
|
||||
assert.equal(args.user_group.description, "All mobile people");
|
||||
templates_render_called = true;
|
||||
return fake_rendered_temp;
|
||||
return $fake_rendered_temp;
|
||||
});
|
||||
|
||||
let user_groups_list_append_called = false;
|
||||
$("#user-groups").append = (rendered_temp) => {
|
||||
assert.equal(rendered_temp, fake_rendered_temp);
|
||||
assert.equal(rendered_temp, $fake_rendered_temp);
|
||||
user_groups_list_append_called = true;
|
||||
};
|
||||
|
||||
@@ -158,7 +158,7 @@ test_ui("populate_user_groups", ({override_rewire, mock_template}) => {
|
||||
|
||||
const all_pills = new Map();
|
||||
|
||||
const pill_container_stub = $(`.pill-container[data-group-pills="${CSS.escape(1)}"]`);
|
||||
const $pill_container_stub = $(`.pill-container[data-group-pills="${CSS.escape(1)}"]`);
|
||||
pills.appendValidatedData = (item) => {
|
||||
const id = item.user_id;
|
||||
assert.ok(!all_pills.has(id));
|
||||
@@ -171,11 +171,11 @@ test_ui("populate_user_groups", ({override_rewire, mock_template}) => {
|
||||
text_cleared = true;
|
||||
};
|
||||
|
||||
const input_field_stub = $.create("fake-input-field");
|
||||
pill_container_stub.children = () => input_field_stub;
|
||||
const $input_field_stub = $.create("fake-input-field");
|
||||
$pill_container_stub.children = () => $input_field_stub;
|
||||
|
||||
let input_typeahead_called = false;
|
||||
input_field_stub.typeahead = (config) => {
|
||||
$input_field_stub.typeahead = (config) => {
|
||||
assert.equal(config.items, 5);
|
||||
assert.ok(config.fixed);
|
||||
assert.ok(config.dropup);
|
||||
@@ -187,9 +187,9 @@ test_ui("populate_user_groups", ({override_rewire, mock_template}) => {
|
||||
assert.equal(typeof config.updater, "function");
|
||||
|
||||
(function test_highlighter() {
|
||||
const fake_person = $.create("fake-person");
|
||||
typeahead_helper.render_person = () => fake_person;
|
||||
assert.equal(config.highlighter(), fake_person);
|
||||
const $fake_person = $.create("fake-person");
|
||||
typeahead_helper.render_person = () => $fake_person;
|
||||
assert.equal(config.highlighter(), $fake_person);
|
||||
})();
|
||||
|
||||
const fake_context = {
|
||||
@@ -236,7 +236,7 @@ test_ui("populate_user_groups", ({override_rewire, mock_template}) => {
|
||||
})();
|
||||
|
||||
(function test_updater() {
|
||||
input_field_stub.text("@ali");
|
||||
$input_field_stub.text("@ali");
|
||||
user_groups.get_user_group_from_id = () => realm_user_group;
|
||||
|
||||
let saved_fade_out_called = false;
|
||||
@@ -334,7 +334,7 @@ test_ui("populate_user_groups", ({override_rewire, mock_template}) => {
|
||||
handler();
|
||||
};
|
||||
|
||||
reset_test_setup(pill_container_stub);
|
||||
reset_test_setup($pill_container_stub);
|
||||
settings_user_groups.set_up();
|
||||
assert.ok(templates_render_called);
|
||||
assert.ok(user_groups_list_append_called);
|
||||
@@ -386,63 +386,63 @@ test_ui("with_external_user", ({override_rewire, mock_template}) => {
|
||||
$.clear_all_elements();
|
||||
|
||||
let user_group_find_called = 0;
|
||||
const user_group_stub = $(`div.user-group[id="${CSS.escape(1)}"]`);
|
||||
const name_field_stub = $.create("fake-name-field");
|
||||
const description_field_stub = $.create("fake-description-field");
|
||||
const input_stub = $.create("fake-input");
|
||||
user_group_stub.find = (elem) => {
|
||||
const $user_group_stub = $(`div.user-group[id="${CSS.escape(1)}"]`);
|
||||
const $name_field_stub = $.create("fake-name-field");
|
||||
const $description_field_stub = $.create("fake-description-field");
|
||||
const $input_stub = $.create("fake-input");
|
||||
$user_group_stub.find = (elem) => {
|
||||
if (elem === ".name") {
|
||||
user_group_find_called += 1;
|
||||
return name_field_stub;
|
||||
return $name_field_stub;
|
||||
}
|
||||
if (elem === ".description") {
|
||||
user_group_find_called += 1;
|
||||
return description_field_stub;
|
||||
return $description_field_stub;
|
||||
}
|
||||
throw new Error(`Unknown element ${elem}`);
|
||||
};
|
||||
|
||||
const pill_container_stub = $(`.pill-container[data-group-pills="${CSS.escape(1)}"]`);
|
||||
const pill_stub = $.create("fake-pill");
|
||||
const $pill_container_stub = $(`.pill-container[data-group-pills="${CSS.escape(1)}"]`);
|
||||
const $pill_stub = $.create("fake-pill");
|
||||
let pill_container_find_called = 0;
|
||||
pill_container_stub.find = (elem) => {
|
||||
$pill_container_stub.find = (elem) => {
|
||||
if (elem === ".input") {
|
||||
pill_container_find_called += 1;
|
||||
return input_stub;
|
||||
return $input_stub;
|
||||
}
|
||||
if (elem === ".pill") {
|
||||
pill_container_find_called += 1;
|
||||
return pill_stub;
|
||||
return $pill_stub;
|
||||
}
|
||||
throw new Error(`Unknown element ${elem}`);
|
||||
};
|
||||
|
||||
input_stub.css = (property, val) => {
|
||||
$input_stub.css = (property, val) => {
|
||||
assert.equal(property, "display");
|
||||
assert.equal(val, "none");
|
||||
};
|
||||
|
||||
// Test the 'off' handlers on the pill-container
|
||||
const turned_off = {};
|
||||
pill_container_stub.off = (event_name, sel = "whole") => {
|
||||
$pill_container_stub.off = (event_name, sel = "whole") => {
|
||||
turned_off[event_name + "/" + sel] = true;
|
||||
};
|
||||
|
||||
const exit_button = $.create("fake-pill-exit");
|
||||
pill_stub.set_find_results(".exit", exit_button);
|
||||
const $exit_button = $.create("fake-pill-exit");
|
||||
$pill_stub.set_find_results(".exit", $exit_button);
|
||||
let exit_button_called = false;
|
||||
exit_button.css = (property, value) => {
|
||||
$exit_button.css = (property, value) => {
|
||||
exit_button_called = true;
|
||||
assert.equal(property, "opacity");
|
||||
assert.equal(value, "0.5");
|
||||
};
|
||||
|
||||
// We return noop because these are already tested, so we skip them
|
||||
pill_container_stub.children = () => noop;
|
||||
$pill_container_stub.children = () => noop;
|
||||
|
||||
$("#user-groups").append = () => noop;
|
||||
|
||||
reset_test_setup(pill_container_stub);
|
||||
reset_test_setup($pill_container_stub);
|
||||
|
||||
settings_user_groups.set_up();
|
||||
|
||||
@@ -451,8 +451,8 @@ test_ui("with_external_user", ({override_rewire, mock_template}) => {
|
||||
|
||||
// Test different handlers with an external user
|
||||
const delete_handler = $("#user-groups").get_on_handler("click", ".delete");
|
||||
const fake_delete = $.create("fk-#user-groups.delete_btn");
|
||||
fake_delete.set_parents_result(".user-group", $(".user-group"));
|
||||
const $fake_delete = $.create("fk-#user-groups.delete_btn");
|
||||
$fake_delete.set_parents_result(".user-group", $(".user-group"));
|
||||
set_parents_result_called += 1;
|
||||
$(".user-group").attr("id", "1");
|
||||
set_attributes_called += 1;
|
||||
@@ -470,11 +470,11 @@ test_ui("with_external_user", ({override_rewire, mock_template}) => {
|
||||
const event = {
|
||||
stopPropagation: noop,
|
||||
};
|
||||
const pill_mouseenter_handler = pill_stub.get_on_handler("mouseenter");
|
||||
const pill_click_handler = pill_container_stub.get_on_handler("click");
|
||||
const pill_mouseenter_handler = $pill_stub.get_on_handler("mouseenter");
|
||||
const pill_click_handler = $pill_container_stub.get_on_handler("click");
|
||||
pill_mouseenter_handler(event);
|
||||
pill_click_handler(event);
|
||||
assert.equal(delete_handler.call(fake_delete), undefined);
|
||||
assert.equal(delete_handler.call($fake_delete), undefined);
|
||||
assert.equal(name_update_handler(), undefined);
|
||||
assert.equal(des_update_handler(), undefined);
|
||||
assert.equal(member_change_handler(), undefined);
|
||||
@@ -524,7 +524,7 @@ test_ui("on_events", ({override_rewire, mock_template}) => {
|
||||
stopPropagation: noop,
|
||||
preventDefault: noop,
|
||||
};
|
||||
const fake_this = $.create("fake-form.admin-user-group-form");
|
||||
const $fake_this = $.create("fake-form.admin-user-group-form");
|
||||
const fake_object_array = [
|
||||
{
|
||||
name: "fake-name",
|
||||
@@ -535,7 +535,7 @@ test_ui("on_events", ({override_rewire, mock_template}) => {
|
||||
value: "fake-value",
|
||||
},
|
||||
];
|
||||
fake_this.serializeArray = () => fake_object_array;
|
||||
$fake_this.serializeArray = () => fake_object_array;
|
||||
channel.post = (opts) => {
|
||||
const data = {
|
||||
members: "[null]",
|
||||
@@ -577,13 +577,13 @@ test_ui("on_events", ({override_rewire, mock_template}) => {
|
||||
})();
|
||||
};
|
||||
|
||||
handler.call(fake_this, event);
|
||||
handler.call($fake_this, event);
|
||||
})();
|
||||
|
||||
(function test_user_groups_delete_click_triggered() {
|
||||
const handler = $("#user-groups").get_on_handler("click", ".delete");
|
||||
const fake_this = $.create("fake-#user-groups.delete_btn");
|
||||
fake_this.set_parents_result(".user-group", $(".user-group"));
|
||||
const $fake_this = $.create("fake-#user-groups.delete_btn");
|
||||
$fake_this.set_parents_result(".user-group", $(".user-group"));
|
||||
$(".user-group").attr("id", "1");
|
||||
|
||||
channel.del = (opts) => {
|
||||
@@ -593,16 +593,16 @@ test_ui("on_events", ({override_rewire, mock_template}) => {
|
||||
assert.equal(opts.url, "/json/user_groups/1");
|
||||
assert.deepEqual(opts.data, data);
|
||||
|
||||
fake_this.text($t({defaultMessage: "fake-text"}));
|
||||
$fake_this.text($t({defaultMessage: "fake-text"}));
|
||||
opts.error();
|
||||
assert.equal(fake_this.text(), "translated: Failed!");
|
||||
assert.equal($fake_this.text(), "translated: Failed!");
|
||||
};
|
||||
|
||||
confirm_dialog.launch = (conf) => {
|
||||
conf.on_click();
|
||||
};
|
||||
|
||||
handler.call(fake_this);
|
||||
handler.call($fake_this);
|
||||
})();
|
||||
|
||||
(function test_user_groups_keypress_enter_triggered() {
|
||||
@@ -625,9 +625,10 @@ test_ui("on_events", ({override_rewire, mock_template}) => {
|
||||
api_endpoint_called = true;
|
||||
};
|
||||
channel.patch = noop;
|
||||
const fake_this = $.create("fake-#user-groups_do_not_blur");
|
||||
const $fake_this = $.create("fake-#user-groups_do_not_blur");
|
||||
const event = {
|
||||
relatedTarget: fake_this,
|
||||
// FIXME: event.relatedTarget should not be a jQuery object
|
||||
relatedTarget: $fake_this,
|
||||
};
|
||||
|
||||
// Any of the blur_exceptions trigger blur event.
|
||||
@@ -645,24 +646,24 @@ test_ui("on_events", ({override_rewire, mock_template}) => {
|
||||
continue;
|
||||
}
|
||||
api_endpoint_called = false;
|
||||
fake_this.closest = (class_name) => {
|
||||
$fake_this.closest = (class_name) => {
|
||||
if (class_name === blur_exception || class_name === user_group_selector) {
|
||||
return [1];
|
||||
}
|
||||
return [];
|
||||
};
|
||||
handler.call(fake_this, event);
|
||||
handler.call($fake_this, event);
|
||||
assert.ok(!api_endpoint_called);
|
||||
}
|
||||
|
||||
api_endpoint_called = false;
|
||||
fake_this.closest = (class_name) => {
|
||||
$fake_this.closest = (class_name) => {
|
||||
if (class_name === ".typeahead") {
|
||||
return [1];
|
||||
}
|
||||
return [];
|
||||
};
|
||||
handler.call(fake_this, event);
|
||||
handler.call($fake_this, event);
|
||||
assert.ok(!api_endpoint_called);
|
||||
|
||||
// Cancel button triggers blur event.
|
||||
@@ -671,7 +672,7 @@ test_ui("on_events", ({override_rewire, mock_template}) => {
|
||||
settings_user_groups_reload_called = true;
|
||||
});
|
||||
api_endpoint_called = false;
|
||||
fake_this.closest = (class_name) => {
|
||||
$fake_this.closest = (class_name) => {
|
||||
if (
|
||||
class_name === ".save-status.btn-danger" ||
|
||||
class_name === user_group_selector
|
||||
@@ -680,7 +681,7 @@ test_ui("on_events", ({override_rewire, mock_template}) => {
|
||||
}
|
||||
return [];
|
||||
};
|
||||
handler.call(fake_this, event);
|
||||
handler.call($fake_this, event);
|
||||
assert.ok(!api_endpoint_called);
|
||||
assert.ok(settings_user_groups_reload_called);
|
||||
}
|
||||
@@ -689,10 +690,10 @@ test_ui("on_events", ({override_rewire, mock_template}) => {
|
||||
(function test_update_cancel_button() {
|
||||
const handler_name = $(user_group_selector).get_on_handler("input", ".name");
|
||||
const handler_desc = $(user_group_selector).get_on_handler("input", ".description");
|
||||
const sib_des = $(description_selector);
|
||||
const sib_name = $(name_selector);
|
||||
sib_name.text($t({defaultMessage: "mobile"}));
|
||||
sib_des.text($t({defaultMessage: "All mobile members"}));
|
||||
const $sib_des = $(description_selector);
|
||||
const $sib_name = $(name_selector);
|
||||
$sib_name.text($t({defaultMessage: "mobile"}));
|
||||
$sib_des.text($t({defaultMessage: "All mobile members"}));
|
||||
|
||||
const group_data = {
|
||||
name: "translated: mobile",
|
||||
@@ -712,8 +713,8 @@ test_ui("on_events", ({override_rewire, mock_template}) => {
|
||||
};
|
||||
|
||||
// Cancel button removed if user group if user group has no changes.
|
||||
const fake_this = $.create("fake-#update_cancel_button");
|
||||
handler_name.call(fake_this);
|
||||
const $fake_this = $.create("fake-#update_cancel_button");
|
||||
handler_name.call($fake_this);
|
||||
assert.ok(cancel_fade_out_called);
|
||||
assert.ok(instructions_fade_out_called);
|
||||
|
||||
@@ -721,14 +722,14 @@ test_ui("on_events", ({override_rewire, mock_template}) => {
|
||||
$(user_group_selector + " .user-group-status").show();
|
||||
cancel_fade_out_called = false;
|
||||
instructions_fade_out_called = false;
|
||||
handler_name.call(fake_this);
|
||||
handler_name.call($fake_this);
|
||||
assert.ok(cancel_fade_out_called);
|
||||
assert.ok(instructions_fade_out_called);
|
||||
|
||||
// Check for handler_desc to achieve 100% coverage.
|
||||
cancel_fade_out_called = false;
|
||||
instructions_fade_out_called = false;
|
||||
handler_desc.call(fake_this);
|
||||
handler_desc.call($fake_this);
|
||||
assert.ok(cancel_fade_out_called);
|
||||
assert.ok(instructions_fade_out_called);
|
||||
})();
|
||||
@@ -736,10 +737,10 @@ test_ui("on_events", ({override_rewire, mock_template}) => {
|
||||
(function test_user_groups_save_group_changes_triggered() {
|
||||
const handler_name = $(user_group_selector).get_on_handler("blur", ".name");
|
||||
const handler_desc = $(user_group_selector).get_on_handler("blur", ".description");
|
||||
const sib_des = $(description_selector);
|
||||
const sib_name = $(name_selector);
|
||||
sib_name.text($t({defaultMessage: "mobile"}));
|
||||
sib_des.text($t({defaultMessage: "All mobile members"}));
|
||||
const $sib_des = $(description_selector);
|
||||
const $sib_name = $(name_selector);
|
||||
$sib_name.text($t({defaultMessage: "mobile"}));
|
||||
$sib_des.text($t({defaultMessage: "All mobile members"}));
|
||||
|
||||
const group_data = {members: new Set([2, 31])};
|
||||
user_groups.get_user_group_from_id = () => group_data;
|
||||
@@ -782,46 +783,47 @@ test_ui("on_events", ({override_rewire, mock_template}) => {
|
||||
assert.ok(saved_fade_to_called);
|
||||
})();
|
||||
(function test_post_error() {
|
||||
const user_group_error = $(user_group_selector + " .user-group-status");
|
||||
user_group_error.show();
|
||||
const $user_group_error = $(user_group_selector + " .user-group-status");
|
||||
$user_group_error.show();
|
||||
ui_report.error = (error_msg, error_obj, ele) => {
|
||||
const xhr = {
|
||||
responseText: '{"msg":"fake-msg"}',
|
||||
};
|
||||
assert.equal(error_msg, "translated HTML: Failed");
|
||||
assert.deepEqual(error_obj, xhr);
|
||||
assert.equal(ele, user_group_error);
|
||||
assert.equal(ele, $user_group_error);
|
||||
};
|
||||
const xhr = {
|
||||
responseText: '{"msg":"fake-msg", "attrib":"val"}',
|
||||
};
|
||||
opts.error(xhr);
|
||||
|
||||
assert.ok(user_group_error.visible());
|
||||
assert.ok($user_group_error.visible());
|
||||
})();
|
||||
};
|
||||
|
||||
const fake_this = $.create("fake-#user-groups_blur_name");
|
||||
fake_this.closest = () => [];
|
||||
fake_this.set_parents_result(user_group_selector, $(user_group_selector));
|
||||
const $fake_this = $.create("fake-#user-groups_blur_name");
|
||||
$fake_this.closest = () => [];
|
||||
$fake_this.set_parents_result(user_group_selector, $(user_group_selector));
|
||||
const event = {
|
||||
relatedTarget: fake_this,
|
||||
// FIXME: event.relatedTarget should not be a jQuery object
|
||||
relatedTarget: $fake_this,
|
||||
};
|
||||
|
||||
api_endpoint_called = false;
|
||||
handler_name.call(fake_this, event);
|
||||
handler_name.call($fake_this, event);
|
||||
assert.ok(api_endpoint_called);
|
||||
|
||||
// Check API endpoint isn't called if name and desc haven't changed.
|
||||
group_data.name = "translated: mobile";
|
||||
group_data.description = "translated: All mobile members";
|
||||
api_endpoint_called = false;
|
||||
handler_name.call(fake_this, event);
|
||||
handler_name.call($fake_this, event);
|
||||
assert.ok(!api_endpoint_called);
|
||||
|
||||
// Check for handler_desc to achieve 100% coverage.
|
||||
api_endpoint_called = false;
|
||||
handler_desc.call(fake_this, event);
|
||||
handler_desc.call($fake_this, event);
|
||||
assert.ok(!api_endpoint_called);
|
||||
})();
|
||||
|
||||
@@ -869,15 +871,16 @@ test_ui("on_events", ({override_rewire, mock_template}) => {
|
||||
})();
|
||||
};
|
||||
|
||||
const fake_this = $.create("fake-#user-groups_blur_input");
|
||||
fake_this.set_parents_result(user_group_selector, $(user_group_selector));
|
||||
fake_this.closest = () => [];
|
||||
const $fake_this = $.create("fake-#user-groups_blur_input");
|
||||
$fake_this.set_parents_result(user_group_selector, $(user_group_selector));
|
||||
$fake_this.closest = () => [];
|
||||
const event = {
|
||||
relatedTarget: fake_this,
|
||||
// FIXME: event.relatedTarget should not be a jQuery object
|
||||
relatedTarget: $fake_this,
|
||||
};
|
||||
|
||||
api_endpoint_called = false;
|
||||
handler.call(fake_this, event);
|
||||
handler.call($fake_this, event);
|
||||
assert.ok(api_endpoint_called);
|
||||
})();
|
||||
});
|
||||
|
||||
@@ -11,30 +11,30 @@ const spoilers = zrequire("spoilers");
|
||||
// This function is taken from rendered_markdown.js and slightly modified.
|
||||
const $array = (array) => {
|
||||
const each = (func) => {
|
||||
for (const [index, elem] of array.entries()) {
|
||||
func.call(this, index, elem);
|
||||
for (const [index, $elem] of array.entries()) {
|
||||
func.call(this, index, $elem);
|
||||
}
|
||||
};
|
||||
return {each};
|
||||
};
|
||||
|
||||
const get_spoiler_elem = (title) => {
|
||||
const block = $.create(`block-${title}`);
|
||||
const header = $.create(`header-${title}`);
|
||||
const content = $.create(`content-${title}`);
|
||||
content.remove = () => {};
|
||||
header.text(title);
|
||||
block.set_find_results(".spoiler-header", header);
|
||||
block.set_find_results(".spoiler-content", content);
|
||||
return block;
|
||||
const $block = $.create(`block-${title}`);
|
||||
const $header = $.create(`header-${title}`);
|
||||
const $content = $.create(`content-${title}`);
|
||||
$content.remove = () => {};
|
||||
$header.text(title);
|
||||
$block.set_find_results(".spoiler-header", $header);
|
||||
$block.set_find_results(".spoiler-content", $content);
|
||||
return $block;
|
||||
};
|
||||
|
||||
run_test("hide spoilers in notifications", () => {
|
||||
const root = $.create("root element");
|
||||
const spoiler_1 = get_spoiler_elem("this is the title");
|
||||
const spoiler_2 = get_spoiler_elem("");
|
||||
root.set_find_results(".spoiler-block", $array([spoiler_1, spoiler_2]));
|
||||
spoilers.hide_spoilers_in_notification(root);
|
||||
assert.equal(spoiler_1.find(".spoiler-header").text(), "this is the title (…)");
|
||||
assert.equal(spoiler_2.find(".spoiler-header").text(), "(…)");
|
||||
const $root = $.create("root element");
|
||||
const $spoiler_1 = get_spoiler_elem("this is the title");
|
||||
const $spoiler_2 = get_spoiler_elem("");
|
||||
$root.set_find_results(".spoiler-block", $array([$spoiler_1, $spoiler_2]));
|
||||
spoilers.hide_spoilers_in_notification($root);
|
||||
assert.equal($spoiler_1.find(".spoiler-header").text(), "this is the title (…)");
|
||||
assert.equal($spoiler_2.find(".spoiler-header").text(), "(…)");
|
||||
});
|
||||
|
||||
@@ -136,32 +136,32 @@ test("update_property", ({override}) => {
|
||||
// Test desktop notifications
|
||||
stream_events.update_property(stream_id, "desktop_notifications", true);
|
||||
assert.equal(sub.desktop_notifications, true);
|
||||
let checkbox = checkbox_for("desktop_notifications");
|
||||
assert.equal(checkbox.prop("checked"), true);
|
||||
let $checkbox = checkbox_for("desktop_notifications");
|
||||
assert.equal($checkbox.prop("checked"), true);
|
||||
|
||||
// Tests audible notifications
|
||||
stream_events.update_property(stream_id, "audible_notifications", true);
|
||||
assert.equal(sub.audible_notifications, true);
|
||||
checkbox = checkbox_for("audible_notifications");
|
||||
assert.equal(checkbox.prop("checked"), true);
|
||||
$checkbox = checkbox_for("audible_notifications");
|
||||
assert.equal($checkbox.prop("checked"), true);
|
||||
|
||||
// Tests push notifications
|
||||
stream_events.update_property(stream_id, "push_notifications", true);
|
||||
assert.equal(sub.push_notifications, true);
|
||||
checkbox = checkbox_for("push_notifications");
|
||||
assert.equal(checkbox.prop("checked"), true);
|
||||
$checkbox = checkbox_for("push_notifications");
|
||||
assert.equal($checkbox.prop("checked"), true);
|
||||
|
||||
// Tests email notifications
|
||||
stream_events.update_property(stream_id, "email_notifications", true);
|
||||
assert.equal(sub.email_notifications, true);
|
||||
checkbox = checkbox_for("email_notifications");
|
||||
assert.equal(checkbox.prop("checked"), true);
|
||||
$checkbox = checkbox_for("email_notifications");
|
||||
assert.equal($checkbox.prop("checked"), true);
|
||||
|
||||
// Tests wildcard_mentions_notify notifications
|
||||
stream_events.update_property(stream_id, "wildcard_mentions_notify", true);
|
||||
assert.equal(sub.wildcard_mentions_notify, true);
|
||||
checkbox = checkbox_for("wildcard_mentions_notify");
|
||||
assert.equal(checkbox.prop("checked"), true);
|
||||
$checkbox = checkbox_for("wildcard_mentions_notify");
|
||||
assert.equal($checkbox.prop("checked"), true);
|
||||
|
||||
// Test name change
|
||||
{
|
||||
@@ -195,8 +195,8 @@ test("update_property", ({override}) => {
|
||||
{
|
||||
override(stream_list, "refresh_pinned_or_unpinned_stream", noop);
|
||||
stream_events.update_property(stream_id, "pin_to_top", true);
|
||||
checkbox = checkbox_for("pin_to_top");
|
||||
assert.equal(checkbox.prop("checked"), true);
|
||||
$checkbox = checkbox_for("pin_to_top");
|
||||
assert.equal($checkbox.prop("checked"), true);
|
||||
}
|
||||
|
||||
// Test stream privacy change event
|
||||
|
||||
@@ -19,7 +19,7 @@ const topic_list = mock_esm("../../static/js/topic_list");
|
||||
mock_esm("../../static/js/keydown_util", {
|
||||
handle: noop,
|
||||
});
|
||||
mock_esm("../../static/js/ui", {get_scroll_element: (element) => element});
|
||||
mock_esm("../../static/js/ui", {get_scroll_element: ($element) => $element});
|
||||
|
||||
const {Filter} = zrequire("../js/filter");
|
||||
const stream_sort = zrequire("stream_sort");
|
||||
@@ -47,41 +47,41 @@ const social = {
|
||||
let num_unread_for_stream;
|
||||
|
||||
function create_devel_sidebar_row({mock_template}) {
|
||||
const devel_count = $.create("devel-count");
|
||||
const subscription_block = $.create("devel-block");
|
||||
const $devel_count = $.create("devel-count");
|
||||
const $subscription_block = $.create("devel-block");
|
||||
|
||||
const sidebar_row = $("<devel sidebar row>");
|
||||
const $sidebar_row = $("<devel-sidebar-row-stub>");
|
||||
|
||||
sidebar_row.set_find_results(".subscription_block", subscription_block);
|
||||
subscription_block.set_find_results(".unread_count", devel_count);
|
||||
$sidebar_row.set_find_results(".subscription_block", $subscription_block);
|
||||
$subscription_block.set_find_results(".unread_count", $devel_count);
|
||||
|
||||
mock_template("stream_sidebar_row.hbs", false, (data) => {
|
||||
assert.equal(data.uri, "#narrow/stream/100-devel");
|
||||
return "<devel sidebar row>";
|
||||
return "<devel-sidebar-row-stub>";
|
||||
});
|
||||
|
||||
num_unread_for_stream = 42;
|
||||
stream_list.create_sidebar_row(devel);
|
||||
assert.equal(devel_count.text(), "42");
|
||||
assert.equal($devel_count.text(), "42");
|
||||
}
|
||||
|
||||
function create_social_sidebar_row({mock_template}) {
|
||||
const social_count = $.create("social-count");
|
||||
const subscription_block = $.create("social-block");
|
||||
const $social_count = $.create("social-count");
|
||||
const $subscription_block = $.create("social-block");
|
||||
|
||||
const sidebar_row = $("<social sidebar row>");
|
||||
const $sidebar_row = $("<social-sidebar-row-stub>");
|
||||
|
||||
sidebar_row.set_find_results(".subscription_block", subscription_block);
|
||||
subscription_block.set_find_results(".unread_count", social_count);
|
||||
$sidebar_row.set_find_results(".subscription_block", $subscription_block);
|
||||
$subscription_block.set_find_results(".unread_count", $social_count);
|
||||
|
||||
mock_template("stream_sidebar_row.hbs", false, (data) => {
|
||||
assert.equal(data.uri, "#narrow/stream/200-social");
|
||||
return "<social sidebar row>";
|
||||
return "<social-sidebar-row-stub>";
|
||||
});
|
||||
|
||||
num_unread_for_stream = 99;
|
||||
stream_list.create_sidebar_row(social);
|
||||
assert.equal(social_count.text(), "99");
|
||||
assert.equal($social_count.text(), "99");
|
||||
}
|
||||
|
||||
function test_ui(label, f) {
|
||||
@@ -105,8 +105,8 @@ test_ui("create_sidebar_row", ({override_rewire, mock_template}) => {
|
||||
create_social_sidebar_row({mock_template});
|
||||
|
||||
const split = '<hr class="stream-split">';
|
||||
const devel_sidebar = $("<devel sidebar row>");
|
||||
const social_sidebar = $("<social sidebar row>");
|
||||
const $devel_sidebar = $("<devel-sidebar-row-stub>");
|
||||
const $social_sidebar = $("<social-sidebar-row-stub>");
|
||||
|
||||
let appended_elems;
|
||||
$("#stream_filters").append = (elems) => {
|
||||
@@ -123,20 +123,20 @@ test_ui("create_sidebar_row", ({override_rewire, mock_template}) => {
|
||||
assert.ok(topic_list_cleared);
|
||||
|
||||
const expected_elems = [
|
||||
devel_sidebar, // pinned
|
||||
$devel_sidebar, // pinned
|
||||
split, // separator
|
||||
social_sidebar, // not pinned
|
||||
$social_sidebar, // not pinned
|
||||
];
|
||||
|
||||
assert.deepEqual(appended_elems, expected_elems);
|
||||
|
||||
const social_li = $("<social sidebar row>");
|
||||
const $social_li = $("<social-sidebar-row-stub>");
|
||||
const stream_id = social.stream_id;
|
||||
|
||||
social_li.length = 0;
|
||||
$social_li.length = 0;
|
||||
|
||||
const privacy_elem = $.create("privacy-stub");
|
||||
social_li.set_find_results(".stream-privacy", privacy_elem);
|
||||
const $privacy_elem = $.create("privacy-stub");
|
||||
$social_li.set_find_results(".stream-privacy", $privacy_elem);
|
||||
|
||||
social.invite_only = true;
|
||||
social.color = "#222222";
|
||||
@@ -147,25 +147,25 @@ test_ui("create_sidebar_row", ({override_rewire, mock_template}) => {
|
||||
return "<div>privacy-html";
|
||||
});
|
||||
stream_list.redraw_stream_privacy(social);
|
||||
assert.equal(privacy_elem.html(), "<div>privacy-html");
|
||||
assert.equal($privacy_elem.html(), "<div>privacy-html");
|
||||
|
||||
stream_list.set_in_home_view(stream_id, false);
|
||||
assert.ok(social_li.hasClass("out_of_home_view"));
|
||||
assert.ok($social_li.hasClass("out_of_home_view"));
|
||||
|
||||
stream_list.set_in_home_view(stream_id, true);
|
||||
assert.ok(!social_li.hasClass("out_of_home_view"));
|
||||
assert.ok(!$social_li.hasClass("out_of_home_view"));
|
||||
|
||||
const row = stream_list.stream_sidebar.get_row(stream_id);
|
||||
override_rewire(stream_data, "is_active", () => true);
|
||||
row.update_whether_active();
|
||||
assert.ok(!social_li.hasClass("inactive_stream"));
|
||||
assert.ok(!$social_li.hasClass("inactive_stream"));
|
||||
|
||||
override_rewire(stream_data, "is_active", () => false);
|
||||
row.update_whether_active();
|
||||
assert.ok(social_li.hasClass("inactive_stream"));
|
||||
assert.ok($social_li.hasClass("inactive_stream"));
|
||||
|
||||
let removed;
|
||||
social_li.remove = () => {
|
||||
$social_li.remove = () => {
|
||||
removed = true;
|
||||
};
|
||||
|
||||
@@ -183,33 +183,33 @@ test_ui("pinned_streams_never_inactive", ({override_rewire, mock_template}) => {
|
||||
create_social_sidebar_row({mock_template});
|
||||
|
||||
// non-pinned streams can be made inactive
|
||||
const social_sidebar = $("<social sidebar row>");
|
||||
const $social_sidebar = $("<social-sidebar-row-stub>");
|
||||
let stream_id = social.stream_id;
|
||||
let row = stream_list.stream_sidebar.get_row(stream_id);
|
||||
override_rewire(stream_data, "is_active", () => false);
|
||||
|
||||
stream_list.build_stream_list();
|
||||
assert.ok(social_sidebar.hasClass("inactive_stream"));
|
||||
assert.ok($social_sidebar.hasClass("inactive_stream"));
|
||||
|
||||
override_rewire(stream_data, "is_active", () => true);
|
||||
row.update_whether_active();
|
||||
assert.ok(!social_sidebar.hasClass("inactive_stream"));
|
||||
assert.ok(!$social_sidebar.hasClass("inactive_stream"));
|
||||
|
||||
override_rewire(stream_data, "is_active", () => false);
|
||||
row.update_whether_active();
|
||||
assert.ok(social_sidebar.hasClass("inactive_stream"));
|
||||
assert.ok($social_sidebar.hasClass("inactive_stream"));
|
||||
|
||||
// pinned streams can never be made inactive
|
||||
const devel_sidebar = $("<devel sidebar row>");
|
||||
const $devel_sidebar = $("<devel-sidebar-row-stub>");
|
||||
stream_id = devel.stream_id;
|
||||
row = stream_list.stream_sidebar.get_row(stream_id);
|
||||
override_rewire(stream_data, "is_active", () => false);
|
||||
|
||||
stream_list.build_stream_list();
|
||||
assert.ok(!devel_sidebar.hasClass("inactive_stream"));
|
||||
assert.ok(!$devel_sidebar.hasClass("inactive_stream"));
|
||||
|
||||
row.update_whether_active();
|
||||
assert.ok(!devel_sidebar.hasClass("inactive_stream"));
|
||||
assert.ok(!$devel_sidebar.hasClass("inactive_stream"));
|
||||
});
|
||||
|
||||
function add_row(sub) {
|
||||
@@ -217,12 +217,12 @@ function add_row(sub) {
|
||||
const row = {
|
||||
update_whether_active() {},
|
||||
get_li() {
|
||||
const html = "<" + sub.name + " sidebar row html>";
|
||||
const obj = $(html);
|
||||
const html = "<" + sub.name + "-sidebar-row-stub>";
|
||||
const $obj = $(html);
|
||||
|
||||
obj.length = 1; // bypass blueslip error
|
||||
$obj.length = 1; // bypass blueslip error
|
||||
|
||||
return obj;
|
||||
return $obj;
|
||||
},
|
||||
};
|
||||
stream_list.stream_sidebar.set_row(sub.stream_id, row);
|
||||
@@ -293,30 +293,30 @@ function elem($obj) {
|
||||
}
|
||||
|
||||
test_ui("zoom_in_and_zoom_out", () => {
|
||||
const label1 = $.create("label1 stub");
|
||||
const label2 = $.create("label2 stub");
|
||||
const $label1 = $.create("label1 stub");
|
||||
const $label2 = $.create("label2 stub");
|
||||
|
||||
label1.show();
|
||||
label2.show();
|
||||
$label1.show();
|
||||
$label2.show();
|
||||
|
||||
assert.ok(label1.visible());
|
||||
assert.ok(label2.visible());
|
||||
assert.ok($label1.visible());
|
||||
assert.ok($label2.visible());
|
||||
|
||||
$.create(".stream-filters-label", {
|
||||
children: [elem(label1), elem(label2)],
|
||||
children: [elem($label1), elem($label2)],
|
||||
});
|
||||
|
||||
const splitter = $.create("hr stub");
|
||||
const $splitter = $.create("hr stub");
|
||||
|
||||
splitter.show();
|
||||
assert.ok(splitter.visible());
|
||||
$splitter.show();
|
||||
assert.ok($splitter.visible());
|
||||
|
||||
$.create(".stream-split", {
|
||||
children: [elem(splitter)],
|
||||
children: [elem($splitter)],
|
||||
});
|
||||
|
||||
const stream_li1 = $.create("stream1 stub");
|
||||
const stream_li2 = $.create("stream2 stub");
|
||||
const $stream_li1 = $.create("stream1 stub");
|
||||
const $stream_li2 = $.create("stream2 stub");
|
||||
|
||||
function make_attr(arg) {
|
||||
return (sel) => {
|
||||
@@ -325,12 +325,12 @@ test_ui("zoom_in_and_zoom_out", () => {
|
||||
};
|
||||
}
|
||||
|
||||
stream_li1.attr = make_attr("42");
|
||||
stream_li1.hide();
|
||||
stream_li2.attr = make_attr("99");
|
||||
$stream_li1.attr = make_attr("42");
|
||||
$stream_li1.hide();
|
||||
$stream_li2.attr = make_attr("99");
|
||||
|
||||
$.create("#stream_filters li.narrow-filter", {
|
||||
children: [elem(stream_li1), elem(stream_li2)],
|
||||
children: [elem($stream_li1), elem($stream_li2)],
|
||||
});
|
||||
|
||||
$("#stream-filters-container")[0] = {
|
||||
@@ -340,26 +340,26 @@ test_ui("zoom_in_and_zoom_out", () => {
|
||||
|
||||
stream_list.zoom_in_topics({stream_id: 42});
|
||||
|
||||
assert.ok(!label1.visible());
|
||||
assert.ok(!label2.visible());
|
||||
assert.ok(!splitter.visible());
|
||||
assert.ok(stream_li1.visible());
|
||||
assert.ok(!stream_li2.visible());
|
||||
assert.ok(!$label1.visible());
|
||||
assert.ok(!$label2.visible());
|
||||
assert.ok(!$splitter.visible());
|
||||
assert.ok($stream_li1.visible());
|
||||
assert.ok(!$stream_li2.visible());
|
||||
assert.ok($("#streams_list").hasClass("zoom-in"));
|
||||
|
||||
$("#stream_filters li.narrow-filter").show = () => {
|
||||
stream_li1.show();
|
||||
stream_li2.show();
|
||||
$stream_li1.show();
|
||||
$stream_li2.show();
|
||||
};
|
||||
|
||||
stream_li1.length = 1;
|
||||
stream_list.zoom_out_topics({stream_li: stream_li1});
|
||||
$stream_li1.length = 1;
|
||||
stream_list.zoom_out_topics({$stream_li: $stream_li1});
|
||||
|
||||
assert.ok(label1.visible());
|
||||
assert.ok(label2.visible());
|
||||
assert.ok(splitter.visible());
|
||||
assert.ok(stream_li1.visible());
|
||||
assert.ok(stream_li2.visible());
|
||||
assert.ok($label1.visible());
|
||||
assert.ok($label2.visible());
|
||||
assert.ok($splitter.visible());
|
||||
assert.ok($stream_li1.visible());
|
||||
assert.ok($stream_li2.visible());
|
||||
assert.ok($("#streams_list").hasClass("zoom-out"));
|
||||
});
|
||||
|
||||
@@ -372,7 +372,7 @@ test_ui("narrowing", ({override_rewire}) => {
|
||||
topic_list.get_stream_li = noop;
|
||||
override_rewire(scroll_util, "scroll_element_into_container", noop);
|
||||
|
||||
assert.ok(!$("<devel sidebar row html>").hasClass("active-filter"));
|
||||
assert.ok(!$("<devel-sidebar-row-stub>").hasClass("active-filter"));
|
||||
|
||||
stream_list.set_event_handlers();
|
||||
|
||||
@@ -380,7 +380,7 @@ test_ui("narrowing", ({override_rewire}) => {
|
||||
|
||||
filter = new Filter([{operator: "stream", operand: "devel"}]);
|
||||
stream_list.handle_narrow_activated(filter);
|
||||
assert.ok($("<devel sidebar row html>").hasClass("active-filter"));
|
||||
assert.ok($("<devel-sidebar-row-stub>").hasClass("active-filter"));
|
||||
|
||||
filter = new Filter([
|
||||
{operator: "stream", operand: "cars"},
|
||||
@@ -388,12 +388,12 @@ test_ui("narrowing", ({override_rewire}) => {
|
||||
]);
|
||||
stream_list.handle_narrow_activated(filter);
|
||||
assert.ok(!$("ul.filters li").hasClass("active-filter"));
|
||||
assert.ok(!$("<cars sidebar row html>").hasClass("active-filter")); // false because of topic
|
||||
assert.ok(!$("<cars-sidebar-row-stub>").hasClass("active-filter")); // false because of topic
|
||||
|
||||
filter = new Filter([{operator: "stream", operand: "cars"}]);
|
||||
stream_list.handle_narrow_activated(filter);
|
||||
assert.ok(!$("ul.filters li").hasClass("active-filter"));
|
||||
assert.ok($("<cars sidebar row html>").hasClass("active-filter"));
|
||||
assert.ok($("<cars-sidebar-row-stub>").hasClass("active-filter"));
|
||||
|
||||
let removed_classes;
|
||||
$("ul#stream_filters li").removeClass = (classes) => {
|
||||
@@ -450,14 +450,14 @@ test_ui("sort_streams", ({override_rewire}) => {
|
||||
|
||||
const split = '<hr class="stream-split">';
|
||||
const expected_elems = [
|
||||
$("<devel sidebar row html>"),
|
||||
$("<Rome sidebar row html>"),
|
||||
$("<test sidebar row html>"),
|
||||
$("<devel-sidebar-row-stub>"),
|
||||
$("<Rome-sidebar-row-stub>"),
|
||||
$("<test-sidebar-row-stub>"),
|
||||
split,
|
||||
$("<announce sidebar row html>"),
|
||||
$("<Denmark sidebar row html>"),
|
||||
$("<announce-sidebar-row-stub>"),
|
||||
$("<Denmark-sidebar-row-stub>"),
|
||||
split,
|
||||
$("<cars sidebar row html>"),
|
||||
$("<cars-sidebar-row-stub>"),
|
||||
];
|
||||
|
||||
assert.deepEqual(appended_elems, expected_elems);
|
||||
@@ -529,11 +529,11 @@ test_ui("separators_only_pinned_and_dormant", ({override_rewire}) => {
|
||||
const split = '<hr class="stream-split">';
|
||||
const expected_elems = [
|
||||
// pinned
|
||||
$("<devel sidebar row html>"),
|
||||
$("<Rome sidebar row html>"),
|
||||
$("<devel-sidebar-row-stub>"),
|
||||
$("<Rome-sidebar-row-stub>"),
|
||||
split,
|
||||
// dormant
|
||||
$("<Denmark sidebar row html>"),
|
||||
$("<Denmark-sidebar-row-stub>"),
|
||||
];
|
||||
|
||||
assert.deepEqual(appended_elems, expected_elems);
|
||||
@@ -573,8 +573,8 @@ test_ui("separators_only_pinned", () => {
|
||||
|
||||
const expected_elems = [
|
||||
// pinned
|
||||
$("<devel sidebar row html>"),
|
||||
$("<Rome sidebar row html>"),
|
||||
$("<devel-sidebar-row-stub>"),
|
||||
$("<Rome-sidebar-row-stub>"),
|
||||
// no separator at the end as no stream follows
|
||||
];
|
||||
|
||||
@@ -591,8 +591,8 @@ test_ui("rename_stream", ({override_rewire, mock_template}) => {
|
||||
|
||||
stream_data.rename_sub(sub, new_name);
|
||||
|
||||
const li_stub = $.create("li stub");
|
||||
li_stub.length = 0;
|
||||
const $li_stub = $.create("li stub");
|
||||
$li_stub.length = 0;
|
||||
|
||||
mock_template("stream_sidebar_row.hbs", false, (payload) => {
|
||||
assert.deepEqual(payload, {
|
||||
@@ -606,12 +606,12 @@ test_ui("rename_stream", ({override_rewire, mock_template}) => {
|
||||
pin_to_top: true,
|
||||
dark_background: payload.dark_background,
|
||||
});
|
||||
return {to_$: () => li_stub};
|
||||
return {to_$: () => $li_stub};
|
||||
});
|
||||
|
||||
let count_updated;
|
||||
override_rewire(stream_list, "update_count_in_dom", (li) => {
|
||||
assert.equal(li, li_stub);
|
||||
override_rewire(stream_list, "update_count_in_dom", ($li) => {
|
||||
assert.equal($li, $li_stub);
|
||||
count_updated = true;
|
||||
});
|
||||
|
||||
@@ -638,17 +638,17 @@ test_ui("refresh_pin", ({override_rewire, mock_template}) => {
|
||||
pin_to_top: true,
|
||||
};
|
||||
|
||||
const li_stub = $.create("li stub");
|
||||
li_stub.length = 0;
|
||||
const $li_stub = $.create("li stub");
|
||||
$li_stub.length = 0;
|
||||
|
||||
mock_template("stream_sidebar_row.hbs", false, () => ({to_$: () => li_stub}));
|
||||
mock_template("stream_sidebar_row.hbs", false, () => ({to_$: () => $li_stub}));
|
||||
|
||||
override_rewire(stream_list, "update_count_in_dom", noop);
|
||||
$("#stream_filters").append = noop;
|
||||
|
||||
let scrolled;
|
||||
override_rewire(stream_list, "scroll_stream_into_view", (li) => {
|
||||
assert.equal(li, li_stub);
|
||||
override_rewire(stream_list, "scroll_stream_into_view", ($li) => {
|
||||
assert.equal($li, $li_stub);
|
||||
scrolled = true;
|
||||
});
|
||||
|
||||
|
||||
@@ -64,32 +64,32 @@ function clear_search_input() {
|
||||
|
||||
run_test("basics", ({override_rewire}) => {
|
||||
let cursor_helper;
|
||||
const input = $(".stream-list-filter");
|
||||
const section = $(".stream_search_section");
|
||||
const $input = $(".stream-list-filter");
|
||||
const $section = $(".stream_search_section");
|
||||
|
||||
expand_sidebar();
|
||||
section.addClass("notdisplayed");
|
||||
$section.addClass("notdisplayed");
|
||||
|
||||
cursor_helper = make_cursor_helper();
|
||||
|
||||
function verify_expanded() {
|
||||
assert.ok(!section.hasClass("notdisplayed"));
|
||||
assert.ok(!$section.hasClass("notdisplayed"));
|
||||
simulate_search_expanded();
|
||||
}
|
||||
|
||||
function verify_focused() {
|
||||
assert.ok(stream_list.searching());
|
||||
assert.ok(input.is_focused());
|
||||
assert.ok($input.is_focused());
|
||||
}
|
||||
|
||||
function verify_blurred() {
|
||||
assert.ok(stream_list.searching());
|
||||
assert.ok(input.is_focused());
|
||||
assert.ok($input.is_focused());
|
||||
}
|
||||
|
||||
function verify_collapsed() {
|
||||
assert.ok(section.hasClass("notdisplayed"));
|
||||
assert.ok(!input.is_focused());
|
||||
assert.ok($section.hasClass("notdisplayed"));
|
||||
assert.ok(!$input.is_focused());
|
||||
assert.ok(!stream_list.searching());
|
||||
simulate_search_collapsed();
|
||||
}
|
||||
@@ -126,7 +126,7 @@ run_test("basics", ({override_rewire}) => {
|
||||
|
||||
(function add_some_text_and_collapse() {
|
||||
cursor_helper = make_cursor_helper();
|
||||
input.val("foo");
|
||||
$input.val("foo");
|
||||
verify_list_updated(() => {
|
||||
toggle_filter();
|
||||
});
|
||||
@@ -149,7 +149,7 @@ run_test("basics", ({override_rewire}) => {
|
||||
stream_list.initiate_search();
|
||||
|
||||
// Clear a non-empty search.
|
||||
input.val("foo");
|
||||
$input.val("foo");
|
||||
verify_list_updated(() => {
|
||||
clear_search_input();
|
||||
});
|
||||
@@ -160,7 +160,7 @@ run_test("basics", ({override_rewire}) => {
|
||||
stream_list.initiate_search();
|
||||
|
||||
// Escape a non-empty search.
|
||||
input.val("foo");
|
||||
$input.val("foo");
|
||||
stream_list.escape_search();
|
||||
verify_blurred();
|
||||
|
||||
@@ -169,7 +169,7 @@ run_test("basics", ({override_rewire}) => {
|
||||
stream_list.initiate_search();
|
||||
|
||||
// Escape an empty search.
|
||||
input.val("");
|
||||
$input.val("");
|
||||
stream_list.escape_search();
|
||||
verify_collapsed();
|
||||
});
|
||||
|
||||
@@ -9,8 +9,8 @@ const $ = require("../zjsunit/zjquery");
|
||||
const denmark_stream_id = 101;
|
||||
|
||||
const ui = mock_esm("../../static/js/ui", {
|
||||
get_content_element: (element) => element,
|
||||
get_scroll_element: (element) => element,
|
||||
get_content_element: ($element) => $element,
|
||||
get_scroll_element: ($element) => $element,
|
||||
});
|
||||
|
||||
mock_esm("../../static/js/hash_util", {
|
||||
@@ -103,16 +103,16 @@ run_test("redraw_left_panel", ({mock_template}) => {
|
||||
$.create("#manage_streams_container .stream-row", {children: sub_stubs});
|
||||
|
||||
let ui_called = false;
|
||||
ui.reset_scrollbar = (elem) => {
|
||||
ui.reset_scrollbar = ($elem) => {
|
||||
ui_called = true;
|
||||
assert.equal(elem, $("#subscription_overlay .streams-list"));
|
||||
assert.equal($elem, $("#subscription_overlay .streams-list"));
|
||||
};
|
||||
|
||||
// Filtering has the side effect of setting the "active" class
|
||||
// on our current stream, even if it doesn't match the filter.
|
||||
const denmark_row = $(`.stream-row[data-stream-id='${CSS.escape(denmark_stream_id)}']`);
|
||||
const $denmark_row = $(`.stream-row[data-stream-id='${CSS.escape(denmark_stream_id)}']`);
|
||||
// sanity check it's not set to active
|
||||
assert.ok(!denmark_row.hasClass("active"));
|
||||
assert.ok(!$denmark_row.hasClass("active"));
|
||||
|
||||
function test_filter(params, expected_streams) {
|
||||
const stream_ids = stream_settings_ui.redraw_left_panel(params);
|
||||
@@ -127,7 +127,7 @@ run_test("redraw_left_panel", ({mock_template}) => {
|
||||
assert.ok(ui_called);
|
||||
|
||||
// The denmark row is active, even though it's not displayed.
|
||||
assert.ok(denmark_row.hasClass("active"));
|
||||
assert.ok($denmark_row.hasClass("active"));
|
||||
|
||||
// Search with multiple keywords
|
||||
test_filter({input: "Denmark, Pol", subscribed_only: false}, [denmark, poland]);
|
||||
|
||||
@@ -19,14 +19,14 @@ run_test("scrub_realm", () => {
|
||||
$.get_initialize_function()();
|
||||
const click_handler = $("body").get_on_handler("click", ".scrub-realm-button");
|
||||
|
||||
const fake_this = $.create("fake-.scrub-realm-button");
|
||||
fake_this.data = (name) => {
|
||||
const $fake_this = $.create("fake-.scrub-realm-button");
|
||||
$fake_this.data = (name) => {
|
||||
assert.equal(name, "string-id");
|
||||
return "zulip";
|
||||
};
|
||||
|
||||
let submit_form_called = false;
|
||||
fake_this.form = {
|
||||
$fake_this.form = {
|
||||
submit: () => {
|
||||
submit_form_called = true;
|
||||
},
|
||||
@@ -36,7 +36,7 @@ run_test("scrub_realm", () => {
|
||||
};
|
||||
|
||||
window.prompt = () => "zulip";
|
||||
click_handler.call(fake_this, event);
|
||||
click_handler.call($fake_this, event);
|
||||
assert.ok(submit_form_called);
|
||||
|
||||
submit_form_called = false;
|
||||
@@ -45,7 +45,7 @@ run_test("scrub_realm", () => {
|
||||
window.alert = () => {
|
||||
alert_called = true;
|
||||
};
|
||||
click_handler.call(fake_this, event);
|
||||
click_handler.call($fake_this, event);
|
||||
assert.ok(!submit_form_called);
|
||||
assert.ok(alert_called);
|
||||
|
||||
|
||||
@@ -210,20 +210,20 @@ run_test("render_date_renders_time_html", () => {
|
||||
const expected_html = $t({defaultMessage: "Today"});
|
||||
|
||||
const attrs = {};
|
||||
const span_stub = $("<span />");
|
||||
const $span_stub = $("<span>");
|
||||
|
||||
span_stub.attr = (name, val) => {
|
||||
$span_stub.attr = (name, val) => {
|
||||
attrs[name] = val;
|
||||
return span_stub;
|
||||
return $span_stub;
|
||||
};
|
||||
|
||||
span_stub.append = (str) => {
|
||||
span_stub.html(str);
|
||||
return span_stub;
|
||||
$span_stub.append = (str) => {
|
||||
$span_stub.html(str);
|
||||
return $span_stub;
|
||||
};
|
||||
|
||||
const actual = timerender.render_date(message_time, undefined, today);
|
||||
assert.equal(actual.html(), expected_html);
|
||||
const $actual = timerender.render_date(message_time, undefined, today);
|
||||
assert.equal($actual.html(), expected_html);
|
||||
assert.equal(attrs["data-tippy-content"], "Friday, April 12, 2019");
|
||||
assert.equal(attrs.class, "timerender0");
|
||||
});
|
||||
@@ -234,19 +234,19 @@ run_test("render_date_renders_time_above_html", () => {
|
||||
const message_time = today;
|
||||
const message_time_above = add(today, {days: -1});
|
||||
|
||||
const span_stub = $("<span />");
|
||||
const $span_stub = $("<span>");
|
||||
|
||||
let appended_val;
|
||||
span_stub.append = (...val) => {
|
||||
$span_stub.append = (...val) => {
|
||||
appended_val = val;
|
||||
return span_stub;
|
||||
return $span_stub;
|
||||
};
|
||||
|
||||
const expected = [
|
||||
'<i class="date-direction fa fa-caret-up"></i>',
|
||||
$("<i>"),
|
||||
$t({defaultMessage: "Yesterday"}),
|
||||
'<hr class="date-line">',
|
||||
'<i class="date-direction fa fa-caret-down"></i>',
|
||||
$("<hr>"),
|
||||
$("<i>"),
|
||||
$t({defaultMessage: "Today"}),
|
||||
];
|
||||
|
||||
|
||||
@@ -104,12 +104,12 @@ run_test("narrowing", ({override_rewire}) => {
|
||||
});
|
||||
|
||||
run_test("update_count_in_dom", () => {
|
||||
function make_elem(elem, count_selector) {
|
||||
const count = $(count_selector);
|
||||
elem.set_find_results(".unread_count", count);
|
||||
count.set_parent(elem);
|
||||
function make_elem($elem, count_selector) {
|
||||
const $count = $(count_selector);
|
||||
$elem.set_find_results(".unread_count", $count);
|
||||
$count.set_parent($elem);
|
||||
|
||||
return elem;
|
||||
return $elem;
|
||||
}
|
||||
|
||||
const counts = {
|
||||
|
||||
@@ -39,7 +39,7 @@ people.add_active_user(levin);
|
||||
people.add_active_user(kitty);
|
||||
|
||||
run_test("render_notifications_for_narrow", ({override_rewire, mock_template}) => {
|
||||
const typing_notifications = $("#typing_notifications");
|
||||
const $typing_notifications = $("#typing_notifications");
|
||||
|
||||
const two_typing_users_ids = [anna.user_id, vronsky.user_id];
|
||||
const three_typing_users_ids = [anna.user_id, vronsky.user_id, levin.user_id];
|
||||
@@ -51,32 +51,32 @@ run_test("render_notifications_for_narrow", ({override_rewire, mock_template}) =
|
||||
// should be rendered but not 'Several people are typing…'
|
||||
override_rewire(typing_events, "get_users_typing_for_narrow", () => two_typing_users_ids);
|
||||
typing_events.render_notifications_for_narrow();
|
||||
assert.ok(typing_notifications.visible());
|
||||
assert.ok(typing_notifications.html().includes(`${anna.full_name} is typing…`));
|
||||
assert.ok(typing_notifications.html().includes(`${vronsky.full_name} is typing…`));
|
||||
assert.ok(!typing_notifications.html().includes("Several people are typing…"));
|
||||
assert.ok($typing_notifications.visible());
|
||||
assert.ok($typing_notifications.html().includes(`${anna.full_name} is typing…`));
|
||||
assert.ok($typing_notifications.html().includes(`${vronsky.full_name} is typing…`));
|
||||
assert.ok(!$typing_notifications.html().includes("Several people are typing…"));
|
||||
|
||||
// Having 3(=MAX_USERS_TO_DISPLAY_NAME) typists should also display only names
|
||||
override_rewire(typing_events, "get_users_typing_for_narrow", () => three_typing_users_ids);
|
||||
typing_events.render_notifications_for_narrow();
|
||||
assert.ok(typing_notifications.visible());
|
||||
assert.ok(typing_notifications.html().includes(`${anna.full_name} is typing…`));
|
||||
assert.ok(typing_notifications.html().includes(`${vronsky.full_name} is typing…`));
|
||||
assert.ok(typing_notifications.html().includes(`${levin.full_name} is typing…`));
|
||||
assert.ok(!typing_notifications.html().includes("Several people are typing…"));
|
||||
assert.ok($typing_notifications.visible());
|
||||
assert.ok($typing_notifications.html().includes(`${anna.full_name} is typing…`));
|
||||
assert.ok($typing_notifications.html().includes(`${vronsky.full_name} is typing…`));
|
||||
assert.ok($typing_notifications.html().includes(`${levin.full_name} is typing…`));
|
||||
assert.ok(!$typing_notifications.html().includes("Several people are typing…"));
|
||||
|
||||
// Having 4(>MAX_USERS_TO_DISPLAY_NAME) typists should display "Several people are typing…"
|
||||
override_rewire(typing_events, "get_users_typing_for_narrow", () => four_typing_users_ids);
|
||||
typing_events.render_notifications_for_narrow();
|
||||
assert.ok(typing_notifications.visible());
|
||||
assert.ok(typing_notifications.html().includes("Several people are typing…"));
|
||||
assert.ok(!typing_notifications.html().includes(`${anna.full_name} is typing…`));
|
||||
assert.ok(!typing_notifications.html().includes(`${vronsky.full_name} is typing…`));
|
||||
assert.ok(!typing_notifications.html().includes(`${levin.full_name} is typing…`));
|
||||
assert.ok(!typing_notifications.html().includes(`${kitty.full_name} is typing…`));
|
||||
assert.ok($typing_notifications.visible());
|
||||
assert.ok($typing_notifications.html().includes("Several people are typing…"));
|
||||
assert.ok(!$typing_notifications.html().includes(`${anna.full_name} is typing…`));
|
||||
assert.ok(!$typing_notifications.html().includes(`${vronsky.full_name} is typing…`));
|
||||
assert.ok(!$typing_notifications.html().includes(`${levin.full_name} is typing…`));
|
||||
assert.ok(!$typing_notifications.html().includes(`${kitty.full_name} is typing…`));
|
||||
|
||||
// #typing_notifications should be hidden when there are no typists.
|
||||
override_rewire(typing_events, "get_users_typing_for_narrow", () => []);
|
||||
typing_events.render_notifications_for_narrow();
|
||||
assert.ok(!typing_notifications.visible());
|
||||
assert.ok(!$typing_notifications.visible());
|
||||
});
|
||||
|
||||
@@ -15,11 +15,7 @@ let uppy_stub;
|
||||
function Uppy(options) {
|
||||
return uppy_stub.call(this, options);
|
||||
}
|
||||
Uppy.Plugin = {
|
||||
prototype: {
|
||||
constructor: null,
|
||||
},
|
||||
};
|
||||
Uppy.UIPlugin = class UIPlugin {};
|
||||
mock_cjs("@uppy/core", Uppy);
|
||||
|
||||
mock_esm("../../static/js/csrf", {csrf_token: "csrf_token"});
|
||||
@@ -36,14 +32,14 @@ function test(label, f) {
|
||||
}
|
||||
|
||||
test("feature_check", ({override}) => {
|
||||
const upload_button = $.create("upload-button-stub");
|
||||
upload_button.addClass("notdisplayed");
|
||||
upload.feature_check(upload_button);
|
||||
assert.ok(upload_button.hasClass("notdisplayed"));
|
||||
const $upload_button = $.create("upload-button-stub");
|
||||
$upload_button.addClass("notdisplayed");
|
||||
upload.feature_check($upload_button);
|
||||
assert.ok($upload_button.hasClass("notdisplayed"));
|
||||
|
||||
override(window, "XMLHttpRequest", () => ({upload: true}));
|
||||
upload.feature_check(upload_button);
|
||||
assert.ok(!upload_button.hasClass("notdisplayed"));
|
||||
upload.feature_check($upload_button);
|
||||
assert.ok(!$upload_button.hasClass("notdisplayed"));
|
||||
});
|
||||
|
||||
test("get_item", () => {
|
||||
|
||||
@@ -194,7 +194,7 @@ test("filter_user_ids", ({override}) => {
|
||||
});
|
||||
|
||||
test("click on user header to toggle display", ({override}) => {
|
||||
const user_filter = $(".user-list-filter");
|
||||
const $user_filter = $(".user-list-filter");
|
||||
|
||||
override(popovers, "hide_all", () => {});
|
||||
override(popovers, "hide_all_except_sidebars", () => {});
|
||||
@@ -205,11 +205,11 @@ test("click on user header to toggle display", ({override}) => {
|
||||
|
||||
assert.ok(!$("#user_search_section").hasClass("notdisplayed"));
|
||||
|
||||
user_filter.val("bla");
|
||||
$user_filter.val("bla");
|
||||
|
||||
$("#userlist-header").trigger("click");
|
||||
assert.ok($("#user_search_section").hasClass("notdisplayed"));
|
||||
assert.equal(user_filter.val(), "");
|
||||
assert.equal($user_filter.val(), "");
|
||||
|
||||
$(".user-list-filter").closest = (selector) => {
|
||||
assert.equal(selector, ".app-main [class^='column-']");
|
||||
|
||||
@@ -282,12 +282,18 @@ run_test("clean_user_content_links", () => {
|
||||
'<a href="http://zulip.zulipdev.com/user_uploads/w/ha/tever/file.png">upload</a> ' +
|
||||
'<a href="http://localhost:NNNN">invalid</a> ' +
|
||||
'<a href="javascript:alert(1)">unsafe</a> ' +
|
||||
'<a href="/#fragment" target="_blank">fragment</a>',
|
||||
'<a href="/#fragment" target="_blank">fragment</a>' +
|
||||
'<div class="message_inline_image">' +
|
||||
'<a href="http://zulip.zulipdev.com/user_uploads/w/ha/tever/inline.png" title="inline image">upload</a> ' +
|
||||
"</div>",
|
||||
),
|
||||
'<a href="http://example.com" target="_blank" rel="noopener noreferrer" title="http://example.com/">good</a> ' +
|
||||
'<a href="http://zulip.zulipdev.com/user_uploads/w/ha/tever/file.png" target="_blank" rel="noopener noreferrer" title="translated: Download file.png">upload</a> ' +
|
||||
"<a>invalid</a> " +
|
||||
"<a>unsafe</a> " +
|
||||
'<a href="/#fragment" title="http://zulip.zulipdev.com/#fragment">fragment</a>',
|
||||
'<a href="/#fragment" title="http://zulip.zulipdev.com/#fragment">fragment</a>' +
|
||||
'<div class="message_inline_image">' +
|
||||
'<a href="http://zulip.zulipdev.com/user_uploads/w/ha/tever/inline.png" target="_blank" rel="noopener noreferrer" aria-label="inline image">upload</a> ' +
|
||||
"</div>",
|
||||
);
|
||||
});
|
||||
|
||||
@@ -35,16 +35,16 @@ const sample_events = [
|
||||
];
|
||||
|
||||
let events;
|
||||
let widget_elem;
|
||||
let $widget_elem;
|
||||
let is_event_handled;
|
||||
let is_widget_activated;
|
||||
|
||||
const fake_poll_widget = {
|
||||
activate(data) {
|
||||
is_widget_activated = true;
|
||||
widget_elem = data.elem;
|
||||
assert.ok(widget_elem.hasClass("widget-content"));
|
||||
widget_elem.handle_events = (e) => {
|
||||
$widget_elem = data.$elem;
|
||||
assert.ok($widget_elem.hasClass("widget-content"));
|
||||
$widget_elem.handle_events = (e) => {
|
||||
is_event_handled = true;
|
||||
assert.notDeepStrictEqual(e, events);
|
||||
events.shift();
|
||||
@@ -65,7 +65,7 @@ const widgetize = zrequire("widgetize");
|
||||
function test(label, f) {
|
||||
run_test(label, ({override}) => {
|
||||
events = [...sample_events];
|
||||
widget_elem = undefined;
|
||||
$widget_elem = undefined;
|
||||
is_event_handled = false;
|
||||
is_widget_activated = false;
|
||||
widgetize.clear_for_testing();
|
||||
@@ -76,10 +76,10 @@ function test(label, f) {
|
||||
test("activate", ({override}) => {
|
||||
// Both widgetize.activate and widgetize.handle_event are tested
|
||||
// here to use the "caching" of widgets
|
||||
const row = $.create("<stub message row>");
|
||||
row.attr("id", "zhome2909");
|
||||
const message_content = $.create("#zhome2909");
|
||||
row.set_find_results(".message_content", message_content);
|
||||
const $row = $.create("<stub message row>");
|
||||
$row.attr("id", "zhome2909");
|
||||
const $message_content = $.create("#zhome2909");
|
||||
$row.set_find_results(".message_content", $message_content);
|
||||
|
||||
let narrow_active;
|
||||
override(narrow_state, "active", () => narrow_active);
|
||||
@@ -94,16 +94,16 @@ test("activate", ({override}) => {
|
||||
assert.equal(data.msg_type, "widget");
|
||||
assert.equal(data.data, "test_data");
|
||||
},
|
||||
row,
|
||||
$row,
|
||||
widget_type: "poll",
|
||||
};
|
||||
|
||||
let is_widget_elem_inserted;
|
||||
|
||||
message_content.append = (elem) => {
|
||||
$message_content.append = ($elem) => {
|
||||
is_widget_elem_inserted = true;
|
||||
assert.equal(elem, widget_elem);
|
||||
assert.ok(elem.hasClass("widget-content"));
|
||||
assert.equal($elem, $widget_elem);
|
||||
assert.ok($elem.hasClass("widget-content"));
|
||||
};
|
||||
|
||||
is_widget_elem_inserted = false;
|
||||
@@ -111,19 +111,19 @@ test("activate", ({override}) => {
|
||||
is_event_handled = false;
|
||||
assert.ok(!widgetize.widget_contents.has(opts.message.id));
|
||||
|
||||
message_content.set_find_results(".widget-content", false);
|
||||
$message_content.set_find_results(".widget-content", false);
|
||||
widgetize.activate(opts);
|
||||
|
||||
assert.ok(is_widget_elem_inserted);
|
||||
assert.ok(is_widget_activated);
|
||||
assert.ok(is_event_handled);
|
||||
assert.equal(widgetize.widget_contents.get(opts.message.id), widget_elem);
|
||||
assert.equal(widgetize.widget_contents.get(opts.message.id), $widget_elem);
|
||||
|
||||
is_widget_elem_inserted = false;
|
||||
is_widget_activated = false;
|
||||
is_event_handled = false;
|
||||
|
||||
message_content.set_find_results(".widget-content", false);
|
||||
$message_content.set_find_results(".widget-content", false);
|
||||
widgetize.activate(opts);
|
||||
|
||||
assert.ok(is_widget_elem_inserted);
|
||||
@@ -135,7 +135,7 @@ test("activate", ({override}) => {
|
||||
is_widget_activated = false;
|
||||
is_event_handled = false;
|
||||
|
||||
message_content.set_find_results(".widget-content", false);
|
||||
$message_content.set_find_results(".widget-content", false);
|
||||
widgetize.activate(opts);
|
||||
|
||||
assert.ok(!is_widget_elem_inserted);
|
||||
@@ -171,7 +171,7 @@ test("activate", ({override}) => {
|
||||
message_id: 2001,
|
||||
sender_id: 102,
|
||||
};
|
||||
widget_elem.handle_events = (e) => {
|
||||
$widget_elem.handle_events = (e) => {
|
||||
is_event_handled = true;
|
||||
assert.deepEqual(e, [post_activate_event]);
|
||||
};
|
||||
@@ -191,7 +191,7 @@ test("activate", ({override}) => {
|
||||
});
|
||||
override(message_lists.current, "get_row", (idx) => {
|
||||
assert.equal(idx, 2001);
|
||||
return row;
|
||||
return $row;
|
||||
});
|
||||
widgetize.set_widgets_for_list();
|
||||
});
|
||||
|
||||
@@ -45,28 +45,28 @@ run_test("basics", () => {
|
||||
|
||||
// Next, look at how several functions correctly simulate setting
|
||||
// and getting for you.
|
||||
const widget = $("#my-widget");
|
||||
const $widget = $("#my-widget");
|
||||
|
||||
widget.attr("data-employee-id", 42);
|
||||
assert.equal(widget.attr("data-employee-id"), 42);
|
||||
assert.equal(widget.data("employee-id"), 42);
|
||||
$widget.attr("data-employee-id", 42);
|
||||
assert.equal($widget.attr("data-employee-id"), 42);
|
||||
assert.equal($widget.data("employee-id"), 42);
|
||||
|
||||
widget.data("department-id", 77);
|
||||
assert.equal(widget.attr("data-department-id"), 77);
|
||||
assert.equal(widget.data("department-id"), 77);
|
||||
$widget.data("department-id", 77);
|
||||
assert.equal($widget.attr("data-department-id"), 77);
|
||||
assert.equal($widget.data("department-id"), 77);
|
||||
|
||||
widget.data("department-name", "hr");
|
||||
assert.equal(widget.attr("data-department-name"), "hr");
|
||||
assert.equal(widget.data("department-name"), "hr");
|
||||
$widget.data("department-name", "hr");
|
||||
assert.equal($widget.attr("data-department-name"), "hr");
|
||||
assert.equal($widget.data("department-name"), "hr");
|
||||
|
||||
widget.html("<b>hello</b>");
|
||||
assert.equal(widget.html(), "<b>hello</b>");
|
||||
$widget.html("<b>hello</b>"); // eslint-disable-line no-jquery/no-parse-html-literal
|
||||
assert.equal($widget.html(), "<b>hello</b>");
|
||||
|
||||
widget.prop("title", "My widget");
|
||||
assert.equal(widget.prop("title"), "My widget");
|
||||
$widget.prop("title", "My widget");
|
||||
assert.equal($widget.prop("title"), "My widget");
|
||||
|
||||
widget.val("42");
|
||||
assert.equal(widget.val(), "42");
|
||||
$widget.val("42");
|
||||
assert.equal($widget.val(), "42");
|
||||
});
|
||||
|
||||
run_test("finding_related_objects", () => {
|
||||
@@ -84,17 +84,17 @@ run_test("finding_related_objects", () => {
|
||||
// But you can set up your tests to simulate DOM relationships.
|
||||
//
|
||||
// We will use set_find_results(), which is a special zjquery helper.
|
||||
const emoji = $('<div class="emoji">');
|
||||
$("#my-message").set_find_results(".emoji", emoji);
|
||||
const $emoji = $("<emoji-stub>");
|
||||
$("#my-message").set_find_results(".emoji", $emoji);
|
||||
|
||||
// And then calling the function produces the desired effect:
|
||||
update_message_emoji("foo.png");
|
||||
assert.equal(emoji.attr("src"), "foo.png");
|
||||
assert.equal($emoji.attr("src"), "foo.png");
|
||||
|
||||
// Sometimes you want to deliberately test paths that do not find an
|
||||
// element. You can pass 'false' as the result for those cases.
|
||||
emoji.set_find_results(".random", false);
|
||||
assert.equal(emoji.find(".random").length, 0);
|
||||
$emoji.set_find_results(".random", false);
|
||||
assert.equal($emoji.find(".random").length, 0);
|
||||
/*
|
||||
An important thing to understand is that zjquery doesn't truly
|
||||
simulate DOM. The way you make relationships work in zjquery
|
||||
@@ -103,12 +103,12 @@ run_test("finding_related_objects", () => {
|
||||
Here is another example.
|
||||
*/
|
||||
|
||||
const my_parents = $("#folder1,#folder4");
|
||||
const elem = $("#folder555");
|
||||
const $my_parents = $("#folder1,#folder4");
|
||||
const $elem = $("#folder555");
|
||||
|
||||
elem.set_parents_result(".folder", my_parents);
|
||||
elem.parents(".folder").addClass("active");
|
||||
assert.ok(my_parents.hasClass("active"));
|
||||
$elem.set_parents_result(".folder", $my_parents);
|
||||
$elem.parents(".folder").addClass("active");
|
||||
assert.ok($my_parents.hasClass("active"));
|
||||
});
|
||||
|
||||
run_test("clicks", () => {
|
||||
@@ -188,12 +188,12 @@ run_test("create", () => {
|
||||
// You can create jQuery objects that aren't tied to any particular
|
||||
// selector, and which just have a name.
|
||||
|
||||
const obj1 = $.create("the table holding employees");
|
||||
const obj2 = $.create("the collection of rows in the table");
|
||||
const $obj1 = $.create("the table holding employees");
|
||||
const $obj2 = $.create("the collection of rows in the table");
|
||||
|
||||
obj1.show();
|
||||
assert.ok(obj1.visible());
|
||||
$obj1.show();
|
||||
assert.ok($obj1.visible());
|
||||
|
||||
obj2.addClass(".striped");
|
||||
assert.ok(obj2.hasClass(".striped"));
|
||||
$obj2.addClass(".striped");
|
||||
assert.ok($obj2.hasClass(".striped"));
|
||||
});
|
||||
|
||||
@@ -331,8 +331,8 @@ class CommonUtils {
|
||||
return false;
|
||||
}
|
||||
|
||||
const row = zulip_test.last_visible_row();
|
||||
if (zulip_test.row_id(row) !== last_msg.id) {
|
||||
const $row = zulip_test.last_visible_row();
|
||||
if (zulip_test.row_id($row) !== last_msg.id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -343,7 +343,7 @@ class CommonUtils {
|
||||
don't add the star icon until the server
|
||||
responds.
|
||||
*/
|
||||
return row.find(".star").length === 1;
|
||||
return $row.find(".star").length === 1;
|
||||
},
|
||||
{},
|
||||
content,
|
||||
@@ -463,6 +463,16 @@ class CommonUtils {
|
||||
assert.deepStrictEqual(last_n_messages, messages);
|
||||
}
|
||||
|
||||
async open_streams_modal(page: Page): Promise<void> {
|
||||
const all_streams_selector = "#add-stream-link";
|
||||
await page.waitForSelector(all_streams_selector, {visible: true});
|
||||
await page.click(all_streams_selector);
|
||||
|
||||
await page.waitForSelector("#subscription_overlay.new-style", {visible: true});
|
||||
const url = await this.page_url_with_fragment(page);
|
||||
assert.ok(url.includes("#streams/all"));
|
||||
}
|
||||
|
||||
async manage_organization(page: Page): Promise<void> {
|
||||
const menu_selector = "#settings-dropdown";
|
||||
await page.waitForSelector(menu_selector, {visible: true});
|
||||
|
||||
@@ -31,8 +31,8 @@ async function copy_messages(
|
||||
$("body").trigger(new $.Event("keydown", {which: 67, ctrlKey: true}));
|
||||
|
||||
// find temp div with copied text
|
||||
const temp_div = $("#copytempdiv");
|
||||
return temp_div
|
||||
const $temp_div = $("#copytempdiv");
|
||||
return $temp_div
|
||||
.children("p")
|
||||
.get()
|
||||
.map((p) => p.textContent!);
|
||||
|
||||
@@ -4,10 +4,10 @@ import common from "../puppeteer_lib/common";
|
||||
|
||||
async function click_delete_and_return_last_msg_id(page: Page): Promise<string | undefined> {
|
||||
return await page.evaluate(() => {
|
||||
const msg = $("#zhome .message_row").last();
|
||||
msg.find(".message_control_button.actions_hover").trigger("click");
|
||||
const $msg = $("#zhome .message_row").last();
|
||||
$msg.find(".message_control_button.actions_hover").trigger("click");
|
||||
$(".delete_message").trigger("click");
|
||||
return msg.attr("id");
|
||||
return $msg.attr("id");
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -4,8 +4,8 @@ import common from "../puppeteer_lib/common";
|
||||
|
||||
async function trigger_edit_last_message(page: Page): Promise<void> {
|
||||
await page.evaluate(() => {
|
||||
const msg = $("#zhome .message_row").last();
|
||||
msg.find(".message_control_button.actions_hover").trigger("click");
|
||||
const $msg = $("#zhome .message_row").last();
|
||||
$msg.find(".message_control_button.actions_hover").trigger("click");
|
||||
$(".popover_edit_message").trigger("click");
|
||||
});
|
||||
await page.waitForSelector(".message_edit_content", {visible: true});
|
||||
|
||||
@@ -128,7 +128,7 @@ async function test_navigations_from_home(page: Page): Promise<void> {
|
||||
await page.evaluate(() =>
|
||||
$(
|
||||
'*[title="Narrow to your private messages with Cordelia, Lear\'s daughter, King Hamlet"]',
|
||||
).click(),
|
||||
).trigger("click"),
|
||||
);
|
||||
await un_narrow_by_clicking_org_icon(page);
|
||||
await expect_recent_topics(page);
|
||||
|
||||
@@ -12,17 +12,17 @@ async function stars_count(page: Page): Promise<number> {
|
||||
|
||||
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) {
|
||||
const $msg = $(`.message_content:contains("${CSS.escape(message)}"):visible`).last();
|
||||
if ($msg.length !== 1) {
|
||||
throw new Error("cannot find test star message");
|
||||
}
|
||||
|
||||
const star_icon = msg.closest(".messagebox").find(".star");
|
||||
if (star_icon.length !== 1) {
|
||||
const $star_icon = $msg.closest(".messagebox").find(".star");
|
||||
if ($star_icon.length !== 1) {
|
||||
throw new Error("cannot find star icon");
|
||||
}
|
||||
|
||||
star_icon.trigger("click");
|
||||
$star_icon.trigger("click");
|
||||
}, message);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import {strict as assert} from "assert";
|
||||
|
||||
import type {ElementHandle, Page} from "puppeteer";
|
||||
import type {Page} from "puppeteer";
|
||||
|
||||
import common from "../puppeteer_lib/common";
|
||||
|
||||
@@ -34,53 +34,11 @@ async function stream_name_error(page: Page): Promise<string> {
|
||||
return await common.get_text_from_selector(page, "#stream_name_error");
|
||||
}
|
||||
|
||||
async function open_streams_modal(page: Page): Promise<void> {
|
||||
const all_streams_selector = "#add-stream-link";
|
||||
await page.waitForSelector(all_streams_selector, {visible: true});
|
||||
await page.click(all_streams_selector);
|
||||
|
||||
await page.waitForSelector("#subscription_overlay.new-style", {visible: true});
|
||||
const url = await common.page_url_with_fragment(page);
|
||||
assert.ok(url.includes("#streams/all"));
|
||||
}
|
||||
|
||||
async function test_subscription_button(page: Page): Promise<void> {
|
||||
const stream_selector = "[data-stream-name='Venice']";
|
||||
const button_selector = `${stream_selector} .sub_unsub_button`;
|
||||
const subscribed_selector = `${button_selector}.checked`;
|
||||
const unsubscribed_selector = `${button_selector}:not(.checked)`;
|
||||
|
||||
async function subscribed(): Promise<ElementHandle | null> {
|
||||
return await page.waitForSelector(subscribed_selector, {visible: true});
|
||||
}
|
||||
|
||||
async function unsubscribed(): Promise<ElementHandle | null> {
|
||||
return await page.waitForSelector(unsubscribed_selector, {visible: true});
|
||||
}
|
||||
|
||||
// Make sure that Venice is even in our list of streams.
|
||||
await page.waitForSelector(stream_selector, {visible: true});
|
||||
await page.waitForSelector(button_selector, {visible: true});
|
||||
|
||||
// Note that we intentionally re-find the button after each click, since
|
||||
// the live-update code may replace the whole row.
|
||||
let button;
|
||||
|
||||
// We assume Venice is already subscribed, so the first line here
|
||||
// should happen immediately.
|
||||
button = await subscribed();
|
||||
await button!.click();
|
||||
button = await unsubscribed();
|
||||
await button!.click();
|
||||
button = await subscribed();
|
||||
await button!.click();
|
||||
button = await unsubscribed();
|
||||
await button!.click();
|
||||
button = await subscribed();
|
||||
}
|
||||
|
||||
async function click_create_new_stream(page: Page): Promise<void> {
|
||||
await page.click("#add_new_subscription .create_stream_button");
|
||||
await page.waitForSelector(".finalize_create_stream", {visible: true});
|
||||
|
||||
// sanity check that desdemona is the initial subsscriber
|
||||
await await_user_visible(page, "desdemona");
|
||||
}
|
||||
|
||||
@@ -205,8 +163,7 @@ async function test_streams_search_feature(page: Page): Promise<void> {
|
||||
|
||||
async function subscriptions_tests(page: Page): Promise<void> {
|
||||
await common.log_in(page);
|
||||
await open_streams_modal(page);
|
||||
await test_subscription_button(page);
|
||||
await common.open_streams_modal(page);
|
||||
await test_stream_creation(page);
|
||||
await test_streams_search_feature(page);
|
||||
}
|
||||
54
frontend_tests/puppeteer_tests/subscribe_toggle.ts
Normal file
54
frontend_tests/puppeteer_tests/subscribe_toggle.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
import type {ElementHandle, Page} from "puppeteer";
|
||||
|
||||
import common from "../puppeteer_lib/common";
|
||||
|
||||
async function test_subscription_button(page: Page): Promise<void> {
|
||||
const stream_selector = "[data-stream-name='Venice']";
|
||||
const button_selector = `${stream_selector} .sub_unsub_button`;
|
||||
const subscribed_selector = `${button_selector}.checked`;
|
||||
const unsubscribed_selector = `${button_selector}:not(.checked)`;
|
||||
|
||||
async function subscribed(): Promise<ElementHandle | null> {
|
||||
return await page.waitForSelector(subscribed_selector, {visible: true});
|
||||
}
|
||||
|
||||
async function unsubscribed(): Promise<ElementHandle | null> {
|
||||
return await page.waitForSelector(unsubscribed_selector, {visible: true});
|
||||
}
|
||||
|
||||
// Make sure that Venice is even in our list of streams.
|
||||
await page.waitForSelector(stream_selector, {visible: true});
|
||||
await page.waitForSelector(button_selector, {visible: true});
|
||||
|
||||
// Note that we intentionally re-find the button after each click, since
|
||||
// the live-update code may replace the whole row.
|
||||
let button;
|
||||
|
||||
// We assume Venice is already subscribed, so the first line here
|
||||
// should happen immediately.
|
||||
button = await subscribed();
|
||||
|
||||
// Toggle subscriptions several times. This test code has been known
|
||||
// to flake, so we add console statements. It appears that the console
|
||||
// statements help prevent the flake, which is probably caused by some
|
||||
// subtle race condition. We will hopefully diagnose the root cause of
|
||||
// the flake, but I am confident that the test will mostly catch actual
|
||||
// bugs in the real code, so as long as the console.info statements help
|
||||
// here, we should just leave them in.
|
||||
for (let i = 0; i < 10; i += 1) {
|
||||
console.info(`\n unsubscribe/subscribe loop ${i}\n\n`);
|
||||
await button!.click();
|
||||
button = await unsubscribed();
|
||||
await button!.click();
|
||||
button = await subscribed();
|
||||
console.info(`\n end loop ${i}\n\n`);
|
||||
}
|
||||
}
|
||||
|
||||
async function subscriptions_tests(page: Page): Promise<void> {
|
||||
await common.log_in(page);
|
||||
await common.open_streams_modal(page);
|
||||
await test_subscription_button(page);
|
||||
}
|
||||
|
||||
common.run_test(subscriptions_tests);
|
||||
@@ -18,6 +18,23 @@ async function user_row(page: Page, name: string): Promise<string> {
|
||||
return `.user_row[data-user-id="${CSS.escape(user_id.toString())}"]`;
|
||||
}
|
||||
|
||||
async function test_reactivation_confirmation_modal(page: Page, fullname: string): Promise<void> {
|
||||
await common.wait_for_micromodal_to_open(page);
|
||||
|
||||
assert.strictEqual(
|
||||
await common.get_text_from_selector(page, ".dialog_heading"),
|
||||
"Reactivate " + fullname,
|
||||
"Reactivate modal has wrong user.",
|
||||
);
|
||||
assert.strictEqual(
|
||||
await common.get_text_from_selector(page, "#dialog_widget_modal .dialog_submit_button"),
|
||||
"Confirm",
|
||||
"Reactivate button has incorrect text.",
|
||||
);
|
||||
await page.click("#dialog_widget_modal .dialog_submit_button");
|
||||
await common.wait_for_micromodal_to_close(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});
|
||||
@@ -45,10 +62,11 @@ async function test_reactivate_user(page: Page): Promise<void> {
|
||||
await page.waitForSelector(cordelia_user_row + " .fa-user-plus");
|
||||
await page.click(cordelia_user_row + " .reactivate");
|
||||
|
||||
await test_reactivation_confirmation_modal(page, common.fullname.cordelia);
|
||||
|
||||
await page.waitForSelector(cordelia_user_row + ":not(.deactivated_user)", {visible: true});
|
||||
cordelia_user_row = await user_row(page, "cordelia");
|
||||
await page.waitForSelector(cordelia_user_row + " .fa-user-times");
|
||||
await page.waitForSelector("#user-field-status", {hidden: true});
|
||||
}
|
||||
|
||||
async function test_deactivated_users_section(page: Page): Promise<void> {
|
||||
@@ -66,6 +84,9 @@ async function test_deactivated_users_section(page: Page): Promise<void> {
|
||||
{visible: true},
|
||||
);
|
||||
await page.click("#admin_deactivated_users_table " + cordelia_user_row + " .reactivate");
|
||||
|
||||
await test_reactivation_confirmation_modal(page, common.fullname.cordelia);
|
||||
|
||||
await page.waitForSelector(
|
||||
"#admin_deactivated_users_table " + cordelia_user_row + " button:not(.reactivate)",
|
||||
{visible: true},
|
||||
@@ -83,6 +104,8 @@ async function test_bot_deactivation_and_reactivation(page: Page): Promise<void>
|
||||
await page.waitForSelector("#bot-field-status", {hidden: true});
|
||||
|
||||
await page.click(default_bot_user_row + " .reactivate");
|
||||
await test_reactivation_confirmation_modal(page, "Zulip Default Bot");
|
||||
|
||||
await page.waitForSelector(default_bot_user_row + ":not(.deactivated_user)", {visible: true});
|
||||
await page.waitForSelector(default_bot_user_row + " .fa-user-times");
|
||||
}
|
||||
|
||||
@@ -188,7 +188,7 @@ exports.mock_cjs = (module_path, obj) => {
|
||||
};
|
||||
|
||||
exports.mock_jquery = ($) => {
|
||||
jquery_function = $;
|
||||
jquery_function = $; // eslint-disable-line no-jquery/variable-pattern
|
||||
return $;
|
||||
};
|
||||
|
||||
|
||||
@@ -43,8 +43,8 @@ function make_zjquery() {
|
||||
const fn = {};
|
||||
|
||||
function new_elem(selector, create_opts) {
|
||||
const elem = FakeElement(selector, {...create_opts});
|
||||
Object.assign(elem, fn);
|
||||
const $elem = FakeElement(selector, {...create_opts});
|
||||
Object.assign($elem, fn);
|
||||
|
||||
// Create a proxy handler to detect missing stubs.
|
||||
//
|
||||
@@ -59,7 +59,7 @@ function make_zjquery() {
|
||||
if (key === "stack") {
|
||||
const error =
|
||||
"\nInstead of doing equality checks on a full object, " +
|
||||
'do `assert_equal(foo.selector, ".some_class")\n';
|
||||
'do `assert_equal($foo.selector, ".some_class")\n';
|
||||
throw new Error(error);
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ function make_zjquery() {
|
||||
},
|
||||
};
|
||||
|
||||
const proxy = new Proxy(elem, handler);
|
||||
const proxy = new Proxy($elem, handler);
|
||||
|
||||
return proxy;
|
||||
}
|
||||
@@ -130,8 +130,8 @@ function make_zjquery() {
|
||||
verify_selector_for_zulip(selector);
|
||||
|
||||
if (!elems.has(selector)) {
|
||||
const elem = new_elem(selector);
|
||||
elems.set(selector, elem);
|
||||
const $elem = new_elem(selector);
|
||||
elems.set(selector, $elem);
|
||||
}
|
||||
return elems.get(selector);
|
||||
};
|
||||
@@ -146,10 +146,10 @@ function make_zjquery() {
|
||||
|
||||
zjquery.create = function (name, opts) {
|
||||
assert.ok(!elems.has(name), "You already created an object with this name!!");
|
||||
const elem = new_elem(name, opts);
|
||||
elems.set(name, elem);
|
||||
const $elem = new_elem(name, opts);
|
||||
elems.set(name, $elem);
|
||||
|
||||
return elem;
|
||||
return $elem;
|
||||
};
|
||||
|
||||
zjquery.trim = function (s) {
|
||||
@@ -158,7 +158,7 @@ function make_zjquery() {
|
||||
|
||||
zjquery.state = function () {
|
||||
// useful for debugging
|
||||
let res = Array.from(elems.values(), (v) => v.debug());
|
||||
let res = Array.from(elems.values(), ($v) => $v.debug());
|
||||
|
||||
res = res.map((v) => [v.selector, v.value, v.shown]);
|
||||
|
||||
@@ -250,4 +250,4 @@ const $ = new Proxy(make_zjquery(), {
|
||||
},
|
||||
});
|
||||
|
||||
module.exports = $;
|
||||
module.exports = $; // eslint-disable-line no-jquery/variable-pattern
|
||||
|
||||
@@ -15,38 +15,38 @@ function FakeElement(selector, opts) {
|
||||
let height;
|
||||
|
||||
const find_results = new Map();
|
||||
let my_parent;
|
||||
let $my_parent;
|
||||
const parents_result = new Map();
|
||||
const properties = new Map();
|
||||
const attrs = new Map();
|
||||
const classes = new Map();
|
||||
const event_store = make_event_store(selector);
|
||||
|
||||
const self = {
|
||||
const $self = {
|
||||
addClass(class_name) {
|
||||
classes.set(class_name, true);
|
||||
return self;
|
||||
return $self;
|
||||
},
|
||||
append(arg) {
|
||||
html = html + arg;
|
||||
return self;
|
||||
return $self;
|
||||
},
|
||||
attr(name, val) {
|
||||
if (val === undefined) {
|
||||
return attrs.get(name);
|
||||
}
|
||||
attrs.set(name, val);
|
||||
return self;
|
||||
return $self;
|
||||
},
|
||||
data(name, val) {
|
||||
if (val === undefined) {
|
||||
return attrs.get("data-" + name);
|
||||
}
|
||||
attrs.set("data-" + name, val);
|
||||
return self;
|
||||
return $self;
|
||||
},
|
||||
delay() {
|
||||
return self;
|
||||
return $self;
|
||||
},
|
||||
debug() {
|
||||
return {
|
||||
@@ -59,22 +59,22 @@ function FakeElement(selector, opts) {
|
||||
if (arg === undefined) {
|
||||
find_results.clear();
|
||||
}
|
||||
return self;
|
||||
return $self;
|
||||
},
|
||||
eq() {
|
||||
return self;
|
||||
return $self;
|
||||
},
|
||||
expectOne() {
|
||||
// silently do nothing
|
||||
return self;
|
||||
return $self;
|
||||
},
|
||||
fadeTo: noop,
|
||||
find(child_selector) {
|
||||
const child = find_results.get(child_selector);
|
||||
if (child) {
|
||||
return child;
|
||||
const $child = find_results.get(child_selector);
|
||||
if ($child) {
|
||||
return $child;
|
||||
}
|
||||
if (child === false) {
|
||||
if ($child === false) {
|
||||
// This is deliberately set to simulate missing find results.
|
||||
// Return an empty array, the most common check is
|
||||
// if ($.find().length) { //success }
|
||||
@@ -84,12 +84,12 @@ function FakeElement(selector, opts) {
|
||||
We need you to simulate the results of $(...).find(...)
|
||||
by using set_find_results. You want something like this:
|
||||
|
||||
const container = ...;
|
||||
const child = ...;
|
||||
container.set_find_results("${child_selector}", child);
|
||||
const $container = ...;
|
||||
const $child = ...;
|
||||
$container.set_find_results("${child_selector}", $child);
|
||||
|
||||
Then calling container.find("${child_selector}") will return
|
||||
the "child" zjquery element.
|
||||
Then calling $container.find("${child_selector}") will return
|
||||
the "$child" zjquery element.
|
||||
|
||||
`);
|
||||
},
|
||||
@@ -107,12 +107,12 @@ function FakeElement(selector, opts) {
|
||||
},
|
||||
hide() {
|
||||
shown = false;
|
||||
return self;
|
||||
return $self;
|
||||
},
|
||||
html(arg) {
|
||||
if (arg !== undefined) {
|
||||
html = arg;
|
||||
return self;
|
||||
return $self;
|
||||
}
|
||||
return html;
|
||||
},
|
||||
@@ -121,9 +121,9 @@ function FakeElement(selector, opts) {
|
||||
return shown;
|
||||
}
|
||||
if (arg === ":focus") {
|
||||
return self.is_focused();
|
||||
return $self.is_focused();
|
||||
}
|
||||
return self;
|
||||
return $self;
|
||||
},
|
||||
is_focused() {
|
||||
// is_focused is not a jQuery thing; this is
|
||||
@@ -132,7 +132,7 @@ function FakeElement(selector, opts) {
|
||||
},
|
||||
off(...args) {
|
||||
event_store.off(...args);
|
||||
return self;
|
||||
return $self;
|
||||
},
|
||||
offset() {
|
||||
return {
|
||||
@@ -142,44 +142,44 @@ function FakeElement(selector, opts) {
|
||||
},
|
||||
on(...args) {
|
||||
event_store.on(...args);
|
||||
return self;
|
||||
return $self;
|
||||
},
|
||||
one(...args) {
|
||||
event_store.one(...args);
|
||||
return self;
|
||||
return $self;
|
||||
},
|
||||
parent() {
|
||||
return my_parent;
|
||||
return $my_parent;
|
||||
},
|
||||
parents(parents_selector) {
|
||||
const result = parents_result.get(parents_selector);
|
||||
const $result = parents_result.get(parents_selector);
|
||||
assert.ok(
|
||||
result,
|
||||
$result,
|
||||
"You need to call set_parents_result for " + parents_selector + " in " + selector,
|
||||
);
|
||||
return result;
|
||||
return $result;
|
||||
},
|
||||
prepend(arg) {
|
||||
html = arg + html;
|
||||
return self;
|
||||
return $self;
|
||||
},
|
||||
prop(name, val) {
|
||||
if (val === undefined) {
|
||||
return properties.get(name);
|
||||
}
|
||||
properties.set(name, val);
|
||||
return self;
|
||||
return $self;
|
||||
},
|
||||
removeAttr(name) {
|
||||
attrs.delete(name);
|
||||
return self;
|
||||
return $self;
|
||||
},
|
||||
removeClass(class_names) {
|
||||
class_names = class_names.split(" ");
|
||||
for (const class_name of class_names) {
|
||||
classes.delete(class_name);
|
||||
}
|
||||
return self;
|
||||
return $self;
|
||||
},
|
||||
remove() {
|
||||
throw new Error(`
|
||||
@@ -193,68 +193,68 @@ function FakeElement(selector, opts) {
|
||||
},
|
||||
removeData: noop,
|
||||
replaceWith() {
|
||||
return self;
|
||||
return $self;
|
||||
},
|
||||
scrollTop() {
|
||||
return self;
|
||||
return $self;
|
||||
},
|
||||
serializeArray() {
|
||||
return self;
|
||||
return $self;
|
||||
},
|
||||
set_find_results(find_selector, jquery_object) {
|
||||
if (jquery_object === undefined) {
|
||||
set_find_results(find_selector, $jquery_object) {
|
||||
if ($jquery_object === undefined) {
|
||||
throw new Error(
|
||||
"Please make the 'find result' be something like $.create('unused')",
|
||||
);
|
||||
}
|
||||
find_results.set(find_selector, jquery_object);
|
||||
find_results.set(find_selector, $jquery_object);
|
||||
},
|
||||
set_height(fake_height) {
|
||||
height = fake_height;
|
||||
},
|
||||
set_parent(parent_elem) {
|
||||
my_parent = parent_elem;
|
||||
set_parent($parent_elem) {
|
||||
$my_parent = $parent_elem;
|
||||
},
|
||||
set_parents_result(selector, result) {
|
||||
parents_result.set(selector, result);
|
||||
set_parents_result(selector, $result) {
|
||||
parents_result.set(selector, $result);
|
||||
},
|
||||
show() {
|
||||
shown = true;
|
||||
return self;
|
||||
return $self;
|
||||
},
|
||||
slice() {
|
||||
return self;
|
||||
return $self;
|
||||
},
|
||||
stop() {
|
||||
return self;
|
||||
return $self;
|
||||
},
|
||||
text(...args) {
|
||||
if (args.length !== 0) {
|
||||
if (args[0] !== undefined) {
|
||||
text = args[0].toString();
|
||||
}
|
||||
return self;
|
||||
return $self;
|
||||
}
|
||||
return text;
|
||||
},
|
||||
toggle(show) {
|
||||
assert.ok([true, false].includes(show));
|
||||
shown = show;
|
||||
return self;
|
||||
return $self;
|
||||
},
|
||||
tooltip() {
|
||||
return self;
|
||||
return $self;
|
||||
},
|
||||
trigger(ev) {
|
||||
event_store.trigger(self, ev);
|
||||
return self;
|
||||
event_store.trigger($self, ev);
|
||||
return $self;
|
||||
},
|
||||
val(...args) {
|
||||
if (args.length === 0) {
|
||||
return value || "";
|
||||
}
|
||||
[value] = args;
|
||||
return self;
|
||||
return $self;
|
||||
},
|
||||
visible() {
|
||||
return shown;
|
||||
@@ -262,34 +262,34 @@ function FakeElement(selector, opts) {
|
||||
};
|
||||
|
||||
if (opts.children) {
|
||||
self.map = (f) => opts.children.map((i, elem) => f(elem, i));
|
||||
self.each = (f) => {
|
||||
$self.map = (f) => opts.children.map((i, elem) => f(elem, i));
|
||||
$self.each = (f) => {
|
||||
for (const child of opts.children) {
|
||||
f.call(child);
|
||||
}
|
||||
};
|
||||
self[Symbol.iterator] = function* () {
|
||||
$self[Symbol.iterator] = function* () {
|
||||
for (const child of opts.children) {
|
||||
yield child;
|
||||
}
|
||||
};
|
||||
|
||||
for (const [i, child] of opts.children.entries()) {
|
||||
self[i] = child;
|
||||
$self[i] = child;
|
||||
}
|
||||
|
||||
self.length = opts.children.length;
|
||||
$self.length = opts.children.length;
|
||||
}
|
||||
|
||||
if (selector[0] === "<") {
|
||||
self.html(selector);
|
||||
$self.html(selector);
|
||||
}
|
||||
|
||||
self.selector = selector;
|
||||
$self.selector = selector;
|
||||
|
||||
self.__zjquery = true;
|
||||
$self.__zjquery = true;
|
||||
|
||||
return self;
|
||||
return $self;
|
||||
}
|
||||
|
||||
function make_event_store(selector) {
|
||||
@@ -394,7 +394,8 @@ function make_event_store(selector) {
|
||||
ev = new FakeEvent(ev);
|
||||
}
|
||||
if (!ev.target) {
|
||||
ev.target = $element;
|
||||
// FIXME: event.target should not be a jQuery object
|
||||
ev.target = $element; // eslint-disable-line no-jquery/variable-pattern
|
||||
}
|
||||
const func = on_functions.get(ev.type);
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user