Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.
 
 
 
 
 
 

551 lignes
15 KiB

  1. import "@testing-library/cypress/add-commands";
  2. import "@4tw/cypress-drag-drop";
  3. import "cypress-real-events/support";
  4. // ***********************************************
  5. // This example commands.js shows you how to
  6. // create various custom commands and overwrite
  7. // existing commands.
  8. //
  9. // For more comprehensive examples of custom
  10. // commands please read more here:
  11. // https://on.cypress.io/custom-commands
  12. // ***********************************************
  13. //
  14. //
  15. // -- This is a parent command --
  16. // Cypress.Commands.add("login", (email, password) => { ... });
  17. //
  18. //
  19. // -- This is a child command --
  20. // Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... });
  21. //
  22. //
  23. // -- This is a dual command --
  24. // Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... });
  25. //
  26. //
  27. // -- This is will overwrite an existing command --
  28. // Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... });
  29. Cypress.Commands.add("login", (email, password) => {
  30. if (!email) {
  31. email = Cypress.config("testUser") || "Administrator";
  32. }
  33. if (!password) {
  34. password = Cypress.env("adminPassword");
  35. }
  36. // cy.session clears all localStorage on new login, so we need to retain the last route
  37. const session_last_route = window.localStorage.getItem("session_last_route");
  38. return cy
  39. .session(
  40. [email, password] || "",
  41. () => {
  42. return cy.request({
  43. url: "/api/method/login",
  44. method: "POST",
  45. body: {
  46. usr: email,
  47. pwd: password,
  48. },
  49. });
  50. },
  51. {
  52. cacheAcrossSpecs: true,
  53. }
  54. )
  55. .then(() => {
  56. if (session_last_route) {
  57. window.localStorage.setItem("session_last_route", session_last_route);
  58. }
  59. });
  60. });
  61. Cypress.Commands.add("call", (method, args) => {
  62. return cy
  63. .window()
  64. .its("xhiveframework.csrf_token")
  65. .then((csrf_token) => {
  66. return cy
  67. .request({
  68. url: `/api/method/${method}`,
  69. method: "POST",
  70. body: args,
  71. headers: {
  72. Accept: "application/json",
  73. "Content-Type": "application/json",
  74. "X-XhiveFramework-CSRF-Token": csrf_token,
  75. },
  76. })
  77. .then((res) => {
  78. expect(res.status).eq(200);
  79. if (method === "logout") {
  80. Cypress.session.clearAllSavedSessions();
  81. }
  82. return res.body;
  83. });
  84. });
  85. });
  86. Cypress.Commands.add("get_list", (doctype, fields = [], filters = []) => {
  87. filters = JSON.stringify(filters);
  88. fields = JSON.stringify(fields);
  89. let url = `/api/resource/${doctype}?fields=${fields}&filters=${filters}`;
  90. return cy
  91. .window()
  92. .its("xhiveframework.csrf_token")
  93. .then((csrf_token) => {
  94. return cy
  95. .request({
  96. method: "GET",
  97. url,
  98. headers: {
  99. Accept: "application/json",
  100. "X-XhiveFramework-CSRF-Token": csrf_token,
  101. },
  102. })
  103. .then((res) => {
  104. expect(res.status).eq(200);
  105. return res.body;
  106. });
  107. });
  108. });
  109. Cypress.Commands.add("get_doc", (doctype, name) => {
  110. return cy
  111. .window()
  112. .its("xhiveframework.csrf_token")
  113. .then((csrf_token) => {
  114. return cy
  115. .request({
  116. method: "GET",
  117. url: `/api/resource/${doctype}/${name}`,
  118. headers: {
  119. Accept: "application/json",
  120. "X-XhiveFramework-CSRF-Token": csrf_token,
  121. },
  122. })
  123. .then((res) => {
  124. expect(res.status).eq(200);
  125. return res.body;
  126. });
  127. });
  128. });
  129. Cypress.Commands.add("remove_doc", (doctype, name) => {
  130. return cy
  131. .window()
  132. .its("xhiveframework.csrf_token")
  133. .then((csrf_token) => {
  134. return cy
  135. .request({
  136. method: "DELETE",
  137. url: `/api/resource/${doctype}/${name}`,
  138. headers: {
  139. Accept: "application/json",
  140. "X-XhiveFramework-CSRF-Token": csrf_token,
  141. },
  142. })
  143. .then((res) => {
  144. expect(res.status).eq(202);
  145. return res.body;
  146. });
  147. });
  148. });
  149. Cypress.Commands.add("create_records", (doc) => {
  150. return cy
  151. .call("xhiveframework.tests.ui_test_helpers.create_if_not_exists", { doc: JSON.stringify(doc) })
  152. .then((r) => r.message);
  153. });
  154. Cypress.Commands.add("set_value", (doctype, name, obj) => {
  155. return cy.call("xhiveframework.client.set_value", {
  156. doctype,
  157. name,
  158. fieldname: obj,
  159. });
  160. });
  161. Cypress.Commands.add("fill_field", (fieldname, value, fieldtype = "Data") => {
  162. cy.get_field(fieldname, fieldtype).as("input");
  163. if (["Date", "Time", "Datetime"].includes(fieldtype)) {
  164. cy.get("@input").click().wait(200);
  165. cy.get(".datepickers-container .datepicker.active").should("exist");
  166. }
  167. if (fieldtype === "Time") {
  168. cy.get("@input").clear().wait(200);
  169. }
  170. if (fieldtype === "Select") {
  171. cy.get("@input").select(value);
  172. } else {
  173. cy.get("@input").type(value, {
  174. waitForAnimations: false,
  175. parseSpecialCharSequences: false,
  176. force: true,
  177. delay: 100,
  178. });
  179. }
  180. return cy.get("@input");
  181. });
  182. Cypress.Commands.add("get_field", (fieldname, fieldtype = "Data") => {
  183. let field_element = fieldtype === "Select" ? "select" : "input";
  184. let selector = `[data-fieldname="${fieldname}"] ${field_element}:visible`;
  185. if (fieldtype === "Text Editor") {
  186. selector = `[data-fieldname="${fieldname}"] .ql-editor[contenteditable=true]:visible`;
  187. }
  188. if (fieldtype === "Code") {
  189. selector = `[data-fieldname="${fieldname}"] .ace_text-input`;
  190. }
  191. if (fieldtype === "Markdown Editor") {
  192. selector = `[data-fieldname="${fieldname}"] .ace-editor-target`;
  193. }
  194. return cy.get(selector).first();
  195. });
  196. Cypress.Commands.add(
  197. "fill_table_field",
  198. (tablefieldname, row_idx, fieldname, value, fieldtype = "Data") => {
  199. cy.get_table_field(tablefieldname, row_idx, fieldname, fieldtype).as("input");
  200. if (["Date", "Time", "Datetime"].includes(fieldtype)) {
  201. cy.get("@input").click().wait(200);
  202. cy.get(".datepickers-container .datepicker.active").should("exist");
  203. }
  204. if (fieldtype === "Time") {
  205. cy.get("@input").clear().wait(200);
  206. }
  207. if (fieldtype === "Select") {
  208. cy.get("@input").select(value);
  209. } else {
  210. cy.get("@input").type(value, { waitForAnimations: false, force: true });
  211. }
  212. return cy.get("@input");
  213. }
  214. );
  215. Cypress.Commands.add(
  216. "get_table_field",
  217. (tablefieldname, row_idx, fieldname, fieldtype = "Data") => {
  218. let selector = `.xhiveframework-control[data-fieldname="${tablefieldname}"]`;
  219. selector += ` [data-idx="${row_idx}"]`;
  220. if (fieldtype === "Text Editor") {
  221. selector += ` [data-fieldname="${fieldname}"] .ql-editor[contenteditable=true]`;
  222. } else if (fieldtype === "Code") {
  223. selector += ` [data-fieldname="${fieldname}"] .ace_text-input`;
  224. } else {
  225. selector += ` [data-fieldname="${fieldname}"]`;
  226. return cy.get(selector).find(".form-control:visible, .static-area:visible").first();
  227. }
  228. return cy.get(selector);
  229. }
  230. );
  231. Cypress.Commands.add("awesomebar", (text) => {
  232. cy.get("#navbar-search").type(`${text}{downarrow}{enter}`, { delay: 700 });
  233. });
  234. Cypress.Commands.add("new_form", (doctype) => {
  235. let dt_in_route = doctype.toLowerCase().replace(/ /g, "-");
  236. cy.visit(`/app/${dt_in_route}/new`);
  237. cy.get("body").should(($body) => {
  238. const dataRoute = $body.attr("data-route");
  239. expect(dataRoute).to.match(new RegExp(`^Form/${doctype}/new-${dt_in_route}-`));
  240. });
  241. cy.get("body").should("have.attr", "data-ajax-state", "complete");
  242. });
  243. Cypress.Commands.add("select_form_tab", (label) => {
  244. cy.get(".form-tabs-list [data-toggle='tab']").contains(label).click().wait(500);
  245. });
  246. Cypress.Commands.add("go_to_list", (doctype) => {
  247. let dt_in_route = doctype.toLowerCase().replace(/ /g, "-");
  248. cy.visit(`/app/${dt_in_route}`);
  249. });
  250. Cypress.Commands.add("clear_cache", () => {
  251. cy.window()
  252. .its("xhiveframework")
  253. .then((xhiveframework) => {
  254. xhiveframework.ui.toolbar.clear_cache();
  255. });
  256. });
  257. Cypress.Commands.add("dialog", (opts) => {
  258. return cy
  259. .window({ log: false })
  260. .its("xhiveframework", { log: false })
  261. .then((xhiveframework) => {
  262. Cypress.log({
  263. name: "dialog",
  264. displayName: "dialog",
  265. message: "xhiveframework.ui.Dialog",
  266. consoleProps: () => {
  267. return {
  268. options: opts,
  269. dialog: d,
  270. };
  271. },
  272. });
  273. var d = new xhiveframework.ui.Dialog(opts);
  274. d.show();
  275. return d;
  276. });
  277. });
  278. Cypress.Commands.add("get_open_dialog", () => {
  279. return cy.get(".modal:visible").last();
  280. });
  281. Cypress.Commands.add("save", () => {
  282. cy.intercept("/api/method/xhiveframework.desk.form.save.savedocs").as("save_call");
  283. cy.get(`.page-container:visible button[data-label="Save"]`).click({ force: true });
  284. cy.wait("@save_call");
  285. });
  286. Cypress.Commands.add("hide_dialog", () => {
  287. cy.wait(500);
  288. cy.get_open_dialog().focus().find(".btn-modal-close").click();
  289. cy.get(".modal:visible").should("not.exist");
  290. });
  291. Cypress.Commands.add("clear_dialogs", () => {
  292. cy.window().then((win) => {
  293. win.$(".modal, .modal-backdrop").remove();
  294. });
  295. cy.get(".modal").should("not.exist");
  296. });
  297. Cypress.Commands.add("clear_datepickers", () => {
  298. cy.window().then((win) => {
  299. win.$(".datepicker").remove();
  300. });
  301. cy.get(".datepicker").should("not.exist");
  302. });
  303. Cypress.Commands.add("insert_doc", (doctype, args, ignore_duplicate) => {
  304. if (!args.doctype) {
  305. args.doctype = doctype;
  306. }
  307. return cy
  308. .window()
  309. .its("xhiveframework.csrf_token")
  310. .then((csrf_token) => {
  311. return cy
  312. .request({
  313. method: "POST",
  314. url: `/api/resource/${doctype}`,
  315. body: args,
  316. headers: {
  317. Accept: "application/json",
  318. "Content-Type": "application/json",
  319. "X-XhiveFramework-CSRF-Token": csrf_token,
  320. },
  321. failOnStatusCode: !ignore_duplicate,
  322. })
  323. .then((res) => {
  324. let status_codes = [200];
  325. if (ignore_duplicate) {
  326. status_codes.push(409);
  327. }
  328. let message = null;
  329. if (ignore_duplicate && !status_codes.includes(res.status)) {
  330. message = `Document insert failed, response: ${JSON.stringify(
  331. res,
  332. null,
  333. "\t"
  334. )}`;
  335. }
  336. expect(res.status).to.be.oneOf(status_codes, message);
  337. return res.body.data;
  338. });
  339. });
  340. });
  341. Cypress.Commands.add("update_doc", (doctype, docname, args) => {
  342. return cy
  343. .window()
  344. .its("xhiveframework.csrf_token")
  345. .then((csrf_token) => {
  346. return cy
  347. .request({
  348. method: "PUT",
  349. url: `/api/resource/${doctype}/${docname}`,
  350. body: args,
  351. headers: {
  352. Accept: "application/json",
  353. "Content-Type": "application/json",
  354. "X-XhiveFramework-CSRF-Token": csrf_token,
  355. },
  356. })
  357. .then((res) => {
  358. expect(res.status).to.eq(200);
  359. return res.body.data;
  360. });
  361. });
  362. });
  363. Cypress.Commands.add("switch_to_user", (user) => {
  364. cy.call("logout");
  365. cy.wait(200);
  366. cy.login(user);
  367. cy.reload();
  368. });
  369. Cypress.Commands.add("add_role", (user, role) => {
  370. cy.window()
  371. .its("xhiveframework")
  372. .then((xhiveframework) => {
  373. const session_user = xhiveframework.session.user;
  374. add_remove_role("add", user, role, session_user);
  375. });
  376. });
  377. Cypress.Commands.add("remove_role", (user, role) => {
  378. cy.window()
  379. .its("xhiveframework")
  380. .then((xhiveframework) => {
  381. const session_user = xhiveframework.session.user;
  382. add_remove_role("remove", user, role, session_user);
  383. });
  384. });
  385. const add_remove_role = (action, user, role, session_user) => {
  386. if (session_user !== "Administrator") {
  387. cy.switch_to_user("Administrator");
  388. }
  389. cy.call("xhiveframework.tests.ui_test_helpers.add_remove_role", {
  390. action: action,
  391. user: user,
  392. role: role,
  393. });
  394. if (session_user !== "Administrator") {
  395. cy.switch_to_user(session_user);
  396. }
  397. };
  398. Cypress.Commands.add("open_list_filter", () => {
  399. cy.get(".filter-section .filter-button").click();
  400. cy.wait(300);
  401. cy.get(".filter-popover").should("exist");
  402. });
  403. Cypress.Commands.add("click_custom_action_button", (name) => {
  404. cy.get(`.custom-actions [data-label="${encodeURIComponent(name)}"]`).click();
  405. });
  406. Cypress.Commands.add("click_action_button", (name) => {
  407. cy.findByRole("button", { name: "Actions" }).click();
  408. cy.get(`.actions-btn-group [data-label="${encodeURIComponent(name)}"]`).click();
  409. });
  410. Cypress.Commands.add("click_menu_button", (name) => {
  411. cy.get(".standard-actions .menu-btn-group > .btn").click();
  412. cy.get(`.menu-btn-group [data-label="${encodeURIComponent(name)}"]`).click();
  413. });
  414. Cypress.Commands.add("clear_filters", () => {
  415. let has_filter = false;
  416. cy.intercept({
  417. method: "POST",
  418. url: "api/method/xhiveframework.model.utils.user_settings.save",
  419. }).as("filter-saved");
  420. cy.get(".filter-section .filter-button").click({ force: true });
  421. cy.wait(300);
  422. cy.get(".filter-popover").should("exist");
  423. cy.get(".filter-popover").then((popover) => {
  424. if (popover.find("input.input-with-feedback")[0].value != "") {
  425. has_filter = true;
  426. }
  427. });
  428. cy.get(".filter-popover").find(".clear-filters").click();
  429. cy.get(".filter-section .filter-button").click();
  430. cy.window()
  431. .its("cur_list")
  432. .then((cur_list) => {
  433. cur_list && cur_list.filter_area && cur_list.filter_area.clear();
  434. has_filter && cy.wait("@filter-saved");
  435. });
  436. });
  437. Cypress.Commands.add("click_modal_primary_button", (btn_name) => {
  438. cy.wait(400);
  439. cy.get(".modal-footer > .standard-actions > .btn-primary")
  440. .contains(btn_name)
  441. .click({ force: true });
  442. });
  443. Cypress.Commands.add("click_sidebar_button", (btn_name) => {
  444. cy.get(".list-group-by-fields .list-link > a").contains(btn_name).click({ force: true });
  445. });
  446. Cypress.Commands.add("click_listview_row_item", (row_no) => {
  447. cy.get(".list-row > .level-left > .list-subject > .level-item > .ellipsis")
  448. .eq(row_no)
  449. .click({ force: true });
  450. });
  451. Cypress.Commands.add("click_listview_row_item_with_text", (text) => {
  452. cy.get(".list-row > .level-left > .list-subject > .level-item > .ellipsis")
  453. .contains(text)
  454. .first()
  455. .click({ force: true });
  456. });
  457. Cypress.Commands.add("click_filter_button", () => {
  458. cy.get(".filter-button").click();
  459. });
  460. Cypress.Commands.add("click_listview_primary_button", (btn_name) => {
  461. cy.get(".primary-action").contains(btn_name).click({ force: true });
  462. });
  463. Cypress.Commands.add("click_doc_primary_button", (btn_name) => {
  464. cy.get(".primary-action").contains(btn_name).click({ force: true });
  465. });
  466. Cypress.Commands.add("click_timeline_action_btn", (btn_name) => {
  467. cy.get(".timeline-message-box .actions .action-btn").contains(btn_name).click();
  468. });
  469. Cypress.Commands.add("select_listview_row_checkbox", (row_no) => {
  470. cy.get(".xhiveframework-list .select-like > .list-row-checkbox").eq(row_no).click();
  471. });
  472. Cypress.Commands.add("click_form_section", (section_name) => {
  473. cy.get(".section-head").contains(section_name).click();
  474. });
  475. const compare_document = (expected, actual) => {
  476. for (const prop in expected) {
  477. if (expected[prop] instanceof Array) {
  478. // recursively compare child documents.
  479. expected[prop].forEach((item, idx) => {
  480. compare_document(item, actual[prop][idx]);
  481. });
  482. } else {
  483. assert.equal(expected[prop], actual[prop], `${prop} should be equal.`);
  484. }
  485. }
  486. };
  487. Cypress.Commands.add("compare_document", (expected_document) => {
  488. cy.window()
  489. .its("cur_frm")
  490. .then((frm) => {
  491. // Don't remove this, cypress can't magically wait for events it has no control over.
  492. cy.wait(1000);
  493. compare_document(expected_document, frm.doc);
  494. });
  495. });