matchers.js 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382
  1. "use strict";
  2. var __defProp = Object.defineProperty;
  3. var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
  4. var __getOwnPropNames = Object.getOwnPropertyNames;
  5. var __hasOwnProp = Object.prototype.hasOwnProperty;
  6. var __export = (target, all) => {
  7. for (var name in all)
  8. __defProp(target, name, { get: all[name], enumerable: true });
  9. };
  10. var __copyProps = (to, from, except, desc) => {
  11. if (from && typeof from === "object" || typeof from === "function") {
  12. for (let key of __getOwnPropNames(from))
  13. if (!__hasOwnProp.call(to, key) && key !== except)
  14. __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  15. }
  16. return to;
  17. };
  18. var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
  19. var matchers_exports = {};
  20. __export(matchers_exports, {
  21. computeMatcherTitleSuffix: () => computeMatcherTitleSuffix,
  22. toBeAttached: () => toBeAttached,
  23. toBeChecked: () => toBeChecked,
  24. toBeDisabled: () => toBeDisabled,
  25. toBeEditable: () => toBeEditable,
  26. toBeEmpty: () => toBeEmpty,
  27. toBeEnabled: () => toBeEnabled,
  28. toBeFocused: () => toBeFocused,
  29. toBeHidden: () => toBeHidden,
  30. toBeInViewport: () => toBeInViewport,
  31. toBeOK: () => toBeOK,
  32. toBeVisible: () => toBeVisible,
  33. toContainClass: () => toContainClass,
  34. toContainText: () => toContainText,
  35. toHaveAccessibleDescription: () => toHaveAccessibleDescription,
  36. toHaveAccessibleErrorMessage: () => toHaveAccessibleErrorMessage,
  37. toHaveAccessibleName: () => toHaveAccessibleName,
  38. toHaveAttribute: () => toHaveAttribute,
  39. toHaveCSS: () => toHaveCSS,
  40. toHaveClass: () => toHaveClass,
  41. toHaveCount: () => toHaveCount,
  42. toHaveId: () => toHaveId,
  43. toHaveJSProperty: () => toHaveJSProperty,
  44. toHaveRole: () => toHaveRole,
  45. toHaveText: () => toHaveText,
  46. toHaveTitle: () => toHaveTitle,
  47. toHaveURL: () => toHaveURL,
  48. toHaveValue: () => toHaveValue,
  49. toHaveValues: () => toHaveValues,
  50. toPass: () => toPass
  51. });
  52. module.exports = __toCommonJS(matchers_exports);
  53. var import_utils = require("playwright-core/lib/utils");
  54. var import_utils2 = require("playwright-core/lib/utils");
  55. var import_util = require("../util");
  56. var import_toBeTruthy = require("./toBeTruthy");
  57. var import_toEqual = require("./toEqual");
  58. var import_toHaveURL = require("./toHaveURL");
  59. var import_toMatchText = require("./toMatchText");
  60. var import_toMatchSnapshot = require("./toMatchSnapshot");
  61. var import_config = require("../common/config");
  62. var import_globals = require("../common/globals");
  63. var import_testInfo = require("../worker/testInfo");
  64. var import_matcherHint = require("./matcherHint");
  65. function toBeAttached(locator, options) {
  66. const attached = !options || options.attached === void 0 || options.attached;
  67. const expected = attached ? "attached" : "detached";
  68. const arg = attached ? "" : "{ attached: false }";
  69. return import_toBeTruthy.toBeTruthy.call(this, "toBeAttached", locator, "Locator", expected, arg, async (isNot, timeout) => {
  70. return await locator._expect(attached ? "to.be.attached" : "to.be.detached", { isNot, timeout });
  71. }, options);
  72. }
  73. function toBeChecked(locator, options) {
  74. const checked = options?.checked;
  75. const indeterminate = options?.indeterminate;
  76. const expectedValue = {
  77. checked,
  78. indeterminate
  79. };
  80. let expected;
  81. let arg;
  82. if (options?.indeterminate) {
  83. expected = "indeterminate";
  84. arg = `{ indeterminate: true }`;
  85. } else {
  86. expected = options?.checked === false ? "unchecked" : "checked";
  87. arg = options?.checked === false ? `{ checked: false }` : "";
  88. }
  89. return import_toBeTruthy.toBeTruthy.call(this, "toBeChecked", locator, "Locator", expected, arg, async (isNot, timeout) => {
  90. return await locator._expect("to.be.checked", { isNot, timeout, expectedValue });
  91. }, options);
  92. }
  93. function toBeDisabled(locator, options) {
  94. return import_toBeTruthy.toBeTruthy.call(this, "toBeDisabled", locator, "Locator", "disabled", "", async (isNot, timeout) => {
  95. return await locator._expect("to.be.disabled", { isNot, timeout });
  96. }, options);
  97. }
  98. function toBeEditable(locator, options) {
  99. const editable = !options || options.editable === void 0 || options.editable;
  100. const expected = editable ? "editable" : "readOnly";
  101. const arg = editable ? "" : "{ editable: false }";
  102. return import_toBeTruthy.toBeTruthy.call(this, "toBeEditable", locator, "Locator", expected, arg, async (isNot, timeout) => {
  103. return await locator._expect(editable ? "to.be.editable" : "to.be.readonly", { isNot, timeout });
  104. }, options);
  105. }
  106. function toBeEmpty(locator, options) {
  107. return import_toBeTruthy.toBeTruthy.call(this, "toBeEmpty", locator, "Locator", "empty", "", async (isNot, timeout) => {
  108. return await locator._expect("to.be.empty", { isNot, timeout });
  109. }, options);
  110. }
  111. function toBeEnabled(locator, options) {
  112. const enabled = !options || options.enabled === void 0 || options.enabled;
  113. const expected = enabled ? "enabled" : "disabled";
  114. const arg = enabled ? "" : "{ enabled: false }";
  115. return import_toBeTruthy.toBeTruthy.call(this, "toBeEnabled", locator, "Locator", expected, arg, async (isNot, timeout) => {
  116. return await locator._expect(enabled ? "to.be.enabled" : "to.be.disabled", { isNot, timeout });
  117. }, options);
  118. }
  119. function toBeFocused(locator, options) {
  120. return import_toBeTruthy.toBeTruthy.call(this, "toBeFocused", locator, "Locator", "focused", "", async (isNot, timeout) => {
  121. return await locator._expect("to.be.focused", { isNot, timeout });
  122. }, options);
  123. }
  124. function toBeHidden(locator, options) {
  125. return import_toBeTruthy.toBeTruthy.call(this, "toBeHidden", locator, "Locator", "hidden", "", async (isNot, timeout) => {
  126. return await locator._expect("to.be.hidden", { isNot, timeout });
  127. }, options);
  128. }
  129. function toBeVisible(locator, options) {
  130. const visible = !options || options.visible === void 0 || options.visible;
  131. const expected = visible ? "visible" : "hidden";
  132. const arg = visible ? "" : "{ visible: false }";
  133. return import_toBeTruthy.toBeTruthy.call(this, "toBeVisible", locator, "Locator", expected, arg, async (isNot, timeout) => {
  134. return await locator._expect(visible ? "to.be.visible" : "to.be.hidden", { isNot, timeout });
  135. }, options);
  136. }
  137. function toBeInViewport(locator, options) {
  138. return import_toBeTruthy.toBeTruthy.call(this, "toBeInViewport", locator, "Locator", "in viewport", "", async (isNot, timeout) => {
  139. return await locator._expect("to.be.in.viewport", { isNot, expectedNumber: options?.ratio, timeout });
  140. }, options);
  141. }
  142. function toContainText(locator, expected, options = {}) {
  143. if (Array.isArray(expected)) {
  144. return import_toEqual.toEqual.call(this, "toContainText", locator, "Locator", async (isNot, timeout) => {
  145. const expectedText = (0, import_utils.serializeExpectedTextValues)(expected, { matchSubstring: true, normalizeWhiteSpace: true, ignoreCase: options.ignoreCase });
  146. return await locator._expect("to.contain.text.array", { expectedText, isNot, useInnerText: options.useInnerText, timeout });
  147. }, expected, { ...options, contains: true });
  148. } else {
  149. return import_toMatchText.toMatchText.call(this, "toContainText", locator, "Locator", async (isNot, timeout) => {
  150. const expectedText = (0, import_utils.serializeExpectedTextValues)([expected], { matchSubstring: true, normalizeWhiteSpace: true, ignoreCase: options.ignoreCase });
  151. return await locator._expect("to.have.text", { expectedText, isNot, useInnerText: options.useInnerText, timeout });
  152. }, expected, { ...options, matchSubstring: true });
  153. }
  154. }
  155. function toHaveAccessibleDescription(locator, expected, options) {
  156. return import_toMatchText.toMatchText.call(this, "toHaveAccessibleDescription", locator, "Locator", async (isNot, timeout) => {
  157. const expectedText = (0, import_utils.serializeExpectedTextValues)([expected], { ignoreCase: options?.ignoreCase, normalizeWhiteSpace: true });
  158. return await locator._expect("to.have.accessible.description", { expectedText, isNot, timeout });
  159. }, expected, options);
  160. }
  161. function toHaveAccessibleName(locator, expected, options) {
  162. return import_toMatchText.toMatchText.call(this, "toHaveAccessibleName", locator, "Locator", async (isNot, timeout) => {
  163. const expectedText = (0, import_utils.serializeExpectedTextValues)([expected], { ignoreCase: options?.ignoreCase, normalizeWhiteSpace: true });
  164. return await locator._expect("to.have.accessible.name", { expectedText, isNot, timeout });
  165. }, expected, options);
  166. }
  167. function toHaveAccessibleErrorMessage(locator, expected, options) {
  168. return import_toMatchText.toMatchText.call(this, "toHaveAccessibleErrorMessage", locator, "Locator", async (isNot, timeout) => {
  169. const expectedText = (0, import_utils.serializeExpectedTextValues)([expected], { ignoreCase: options?.ignoreCase, normalizeWhiteSpace: true });
  170. return await locator._expect("to.have.accessible.error.message", { expectedText, isNot, timeout });
  171. }, expected, options);
  172. }
  173. function toHaveAttribute(locator, name, expected, options) {
  174. if (!options) {
  175. if (typeof expected === "object" && !(0, import_utils.isRegExp)(expected)) {
  176. options = expected;
  177. expected = void 0;
  178. }
  179. }
  180. if (expected === void 0) {
  181. return import_toBeTruthy.toBeTruthy.call(this, "toHaveAttribute", locator, "Locator", "have attribute", "", async (isNot, timeout) => {
  182. return await locator._expect("to.have.attribute", { expressionArg: name, isNot, timeout });
  183. }, options);
  184. }
  185. return import_toMatchText.toMatchText.call(this, "toHaveAttribute", locator, "Locator", async (isNot, timeout) => {
  186. const expectedText = (0, import_utils.serializeExpectedTextValues)([expected], { ignoreCase: options?.ignoreCase });
  187. return await locator._expect("to.have.attribute.value", { expressionArg: name, expectedText, isNot, timeout });
  188. }, expected, options);
  189. }
  190. function toHaveClass(locator, expected, options) {
  191. if (Array.isArray(expected)) {
  192. return import_toEqual.toEqual.call(this, "toHaveClass", locator, "Locator", async (isNot, timeout) => {
  193. const expectedText = (0, import_utils.serializeExpectedTextValues)(expected);
  194. return await locator._expect("to.have.class.array", { expectedText, isNot, timeout });
  195. }, expected, options);
  196. } else {
  197. return import_toMatchText.toMatchText.call(this, "toHaveClass", locator, "Locator", async (isNot, timeout) => {
  198. const expectedText = (0, import_utils.serializeExpectedTextValues)([expected]);
  199. return await locator._expect("to.have.class", { expectedText, isNot, timeout });
  200. }, expected, options);
  201. }
  202. }
  203. function toContainClass(locator, expected, options) {
  204. if (Array.isArray(expected)) {
  205. if (expected.some((e) => (0, import_utils.isRegExp)(e)))
  206. throw new Error(`"expected" argument in toContainClass cannot contain RegExp values`);
  207. return import_toEqual.toEqual.call(this, "toContainClass", locator, "Locator", async (isNot, timeout) => {
  208. const expectedText = (0, import_utils.serializeExpectedTextValues)(expected);
  209. return await locator._expect("to.contain.class.array", { expectedText, isNot, timeout });
  210. }, expected, options);
  211. } else {
  212. if ((0, import_utils.isRegExp)(expected))
  213. throw new Error(`"expected" argument in toContainClass cannot be a RegExp value`);
  214. return import_toMatchText.toMatchText.call(this, "toContainClass", locator, "Locator", async (isNot, timeout) => {
  215. const expectedText = (0, import_utils.serializeExpectedTextValues)([expected]);
  216. return await locator._expect("to.contain.class", { expectedText, isNot, timeout });
  217. }, expected, options);
  218. }
  219. }
  220. function toHaveCount(locator, expected, options) {
  221. return import_toEqual.toEqual.call(this, "toHaveCount", locator, "Locator", async (isNot, timeout) => {
  222. return await locator._expect("to.have.count", { expectedNumber: expected, isNot, timeout });
  223. }, expected, options);
  224. }
  225. function toHaveCSS(locator, name, expected, options) {
  226. return import_toMatchText.toMatchText.call(this, "toHaveCSS", locator, "Locator", async (isNot, timeout) => {
  227. const expectedText = (0, import_utils.serializeExpectedTextValues)([expected]);
  228. return await locator._expect("to.have.css", { expressionArg: name, expectedText, isNot, timeout });
  229. }, expected, options);
  230. }
  231. function toHaveId(locator, expected, options) {
  232. return import_toMatchText.toMatchText.call(this, "toHaveId", locator, "Locator", async (isNot, timeout) => {
  233. const expectedText = (0, import_utils.serializeExpectedTextValues)([expected]);
  234. return await locator._expect("to.have.id", { expectedText, isNot, timeout });
  235. }, expected, options);
  236. }
  237. function toHaveJSProperty(locator, name, expected, options) {
  238. return import_toEqual.toEqual.call(this, "toHaveJSProperty", locator, "Locator", async (isNot, timeout) => {
  239. return await locator._expect("to.have.property", { expressionArg: name, expectedValue: expected, isNot, timeout });
  240. }, expected, options);
  241. }
  242. function toHaveRole(locator, expected, options) {
  243. if (!(0, import_utils.isString)(expected))
  244. throw new Error(`"role" argument in toHaveRole must be a string`);
  245. return import_toMatchText.toMatchText.call(this, "toHaveRole", locator, "Locator", async (isNot, timeout) => {
  246. const expectedText = (0, import_utils.serializeExpectedTextValues)([expected]);
  247. return await locator._expect("to.have.role", { expectedText, isNot, timeout });
  248. }, expected, options);
  249. }
  250. function toHaveText(locator, expected, options = {}) {
  251. if (Array.isArray(expected)) {
  252. return import_toEqual.toEqual.call(this, "toHaveText", locator, "Locator", async (isNot, timeout) => {
  253. const expectedText = (0, import_utils.serializeExpectedTextValues)(expected, { normalizeWhiteSpace: true, ignoreCase: options.ignoreCase });
  254. return await locator._expect("to.have.text.array", { expectedText, isNot, useInnerText: options?.useInnerText, timeout });
  255. }, expected, options);
  256. } else {
  257. return import_toMatchText.toMatchText.call(this, "toHaveText", locator, "Locator", async (isNot, timeout) => {
  258. const expectedText = (0, import_utils.serializeExpectedTextValues)([expected], { normalizeWhiteSpace: true, ignoreCase: options.ignoreCase });
  259. return await locator._expect("to.have.text", { expectedText, isNot, useInnerText: options?.useInnerText, timeout });
  260. }, expected, options);
  261. }
  262. }
  263. function toHaveValue(locator, expected, options) {
  264. return import_toMatchText.toMatchText.call(this, "toHaveValue", locator, "Locator", async (isNot, timeout) => {
  265. const expectedText = (0, import_utils.serializeExpectedTextValues)([expected]);
  266. return await locator._expect("to.have.value", { expectedText, isNot, timeout });
  267. }, expected, options);
  268. }
  269. function toHaveValues(locator, expected, options) {
  270. return import_toEqual.toEqual.call(this, "toHaveValues", locator, "Locator", async (isNot, timeout) => {
  271. const expectedText = (0, import_utils.serializeExpectedTextValues)(expected);
  272. return await locator._expect("to.have.values", { expectedText, isNot, timeout });
  273. }, expected, options);
  274. }
  275. function toHaveTitle(page, expected, options = {}) {
  276. return import_toMatchText.toMatchText.call(this, "toHaveTitle", page, "Page", async (isNot, timeout) => {
  277. const expectedText = (0, import_utils.serializeExpectedTextValues)([expected], { normalizeWhiteSpace: true });
  278. return await page.mainFrame()._expect("to.have.title", { expectedText, isNot, timeout });
  279. }, expected, options);
  280. }
  281. function toHaveURL(page, expected, options) {
  282. if (typeof expected === "function")
  283. return import_toHaveURL.toHaveURLWithPredicate.call(this, page, expected, options);
  284. const baseURL = page.context()._options.baseURL;
  285. expected = typeof expected === "string" ? (0, import_utils.constructURLBasedOnBaseURL)(baseURL, expected) : expected;
  286. return import_toMatchText.toMatchText.call(this, "toHaveURL", page, "Page", async (isNot, timeout) => {
  287. const expectedText = (0, import_utils.serializeExpectedTextValues)([expected], { ignoreCase: options?.ignoreCase });
  288. return await page.mainFrame()._expect("to.have.url", { expectedText, isNot, timeout });
  289. }, expected, options);
  290. }
  291. async function toBeOK(response) {
  292. const matcherName = "toBeOK";
  293. (0, import_util.expectTypes)(response, ["APIResponse"], matcherName);
  294. const contentType = response.headers()["content-type"];
  295. const isTextEncoding = contentType && (0, import_utils.isTextualMimeType)(contentType);
  296. const [log, text] = this.isNot === response.ok() ? await Promise.all([
  297. response._fetchLog(),
  298. isTextEncoding ? response.text() : null
  299. ]) : [];
  300. const message = () => (0, import_matcherHint.formatMatcherMessage)(this, {
  301. matcherName,
  302. receiver: "response",
  303. expectation: "",
  304. log
  305. }) + (text === null ? "" : `
  306. Response text:
  307. ${import_utils2.colors.dim(text?.substring(0, 1e3) || "")}`);
  308. const pass = response.ok();
  309. return { message, pass };
  310. }
  311. async function toPass(callback, options = {}) {
  312. const testInfo = (0, import_globals.currentTestInfo)();
  313. const timeout = (0, import_config.takeFirst)(options.timeout, testInfo?._projectInternal.expect?.toPass?.timeout, 0);
  314. const intervals = (0, import_config.takeFirst)(options.intervals, testInfo?._projectInternal.expect?.toPass?.intervals, [100, 250, 500, 1e3]);
  315. const { deadline, timeoutMessage } = testInfo ? testInfo._deadlineForMatcher(timeout) : import_testInfo.TestInfoImpl._defaultDeadlineForMatcher(timeout);
  316. const result = await (0, import_utils.pollAgainstDeadline)(async () => {
  317. if (testInfo && (0, import_globals.currentTestInfo)() !== testInfo)
  318. return { continuePolling: false, result: void 0 };
  319. try {
  320. await callback();
  321. return { continuePolling: !!this.isNot, result: void 0 };
  322. } catch (e) {
  323. return { continuePolling: !this.isNot, result: e };
  324. }
  325. }, deadline, intervals);
  326. if (result.timedOut) {
  327. const message = result.result ? [
  328. result.result.message,
  329. "",
  330. `Call Log:`,
  331. `- ${timeoutMessage}`
  332. ].join("\n") : timeoutMessage;
  333. return { message: () => message, pass: !!this.isNot };
  334. }
  335. return { pass: !this.isNot, message: () => "" };
  336. }
  337. function computeMatcherTitleSuffix(matcherName, receiver, args) {
  338. if (matcherName === "toHaveScreenshot") {
  339. const title = (0, import_toMatchSnapshot.toHaveScreenshotStepTitle)(...args);
  340. return { short: title ? `(${title})` : "" };
  341. }
  342. if (receiver && typeof receiver === "object" && receiver.constructor?.name === "Locator") {
  343. try {
  344. return { long: " " + (0, import_utils.asLocatorDescription)("javascript", receiver._selector) };
  345. } catch {
  346. }
  347. }
  348. return {};
  349. }
  350. // Annotate the CommonJS export names for ESM import in node:
  351. 0 && (module.exports = {
  352. computeMatcherTitleSuffix,
  353. toBeAttached,
  354. toBeChecked,
  355. toBeDisabled,
  356. toBeEditable,
  357. toBeEmpty,
  358. toBeEnabled,
  359. toBeFocused,
  360. toBeHidden,
  361. toBeInViewport,
  362. toBeOK,
  363. toBeVisible,
  364. toContainClass,
  365. toContainText,
  366. toHaveAccessibleDescription,
  367. toHaveAccessibleErrorMessage,
  368. toHaveAccessibleName,
  369. toHaveAttribute,
  370. toHaveCSS,
  371. toHaveClass,
  372. toHaveCount,
  373. toHaveId,
  374. toHaveJSProperty,
  375. toHaveRole,
  376. toHaveText,
  377. toHaveTitle,
  378. toHaveURL,
  379. toHaveValue,
  380. toHaveValues,
  381. toPass
  382. });