Cypress自动化测试框架基础(二)

第一章、Queries(查询方法)

一、cy.get( )

1、语法

默认使用cssSelector定位元素

subject为DOM元素

cy.get(selector)
cy.get(alias)
cy.get(selector, options)
cy.get(alias, options)

2、用法

cy.get('.list > li') // Yield the <li>'s in .list

3、参数:

3.1、selector (String selector)

        用于过滤匹配 DOM 元素的选择器。

3.2、alias (String)

  • 使用命令定义并使用别名的字符和名称 .as() 引用的别名。使用cy.get( @ 别名来访问jQuery对象)
  • 您可以使用cy.get( ) 定位基本元素、常规对象甚至 DOM 元素的别名。
  • 当对 DOM 元素使用别名时,如果之前使用别名的 DOM 元素已经过时,cypress将再次查询 DOM。

3.3、options (Object)

4、返回值

   cy.get() 是 Cypress 中用于选择 DOM 元素的命令之一。它的原理是使用css选择器(selector)来查找页面中符合条件的元素,并将这些元素包装成一个 jQuery 对象,以便 Cypress 可以在之后的测试中对这些元素进行操作。

        具体地说,当 Cypress 执行 cy.get(selector) 命令时,它会首先等待页面上至少存在一个与选择器匹配的元素。如果等待超时,Cypress 将会抛出一个错误,测试将会失败。如果有一个或多个匹配的元素被找到,Cypress 将返回一个包含这些元素的 jQuery 对象。此时,我们就可以使用 Cypress 提供的其他命令,如 click()type()should() 等对这些元素进行操作。

        需要注意的是,cy.get() 命令返回的是一个 jQuery 对象,而不是 DOM 元素本身。这意味着如果我们想要访问元素的原生属性或方法,需要使用 .get() 方法来获取实际的 DOM 元素。例如,如果我们想要获取一个元素的文本内容,可以使用 cy.get(selector).invoke('text') 命令,也可以使用 cy.get(selector).get(0).textContent 来获取。

获取多个元素时,它会返回一个包含多个元素的 jQuery 对象。这个 jQuery 对象与普通的 jQuery 对象类似,它可以对所有匹配到的元素执行相同的操作

二、.children( )

1、语法

.children()
.children(selector)
.children(options)
.children(selector, options)

2、用法

正确用法:

cy.get('nav').children() // Yield children of nav

错误用法:

cy.children() // Errors, cannot be chained off 'cy'
cy.clock().children() // Errors, 'clock' does not yield DOM elements

3、参数

3.1、selector (String selector)

3.2、options (Object)

4、返回值

  • .children()方法返回找到的新的 DOM 元素,可以使用 Cypress 命令继续对这些元素进行操作;
  • .children()是一个查询方法,可以与其他 Cypress 命令链接起来使用。

        具体来说,.children()方法会查找调用它的 DOM 元素的直接子元素,并将找到的所有子元素作为结果返回。返回结果可以直接用 Cypress 命令链式调用其他 Cypress 命令进行操作,例如使用.eq()方法获取特定索引位置的子元素。

        同时,由于.children()是一个查询方法,它不会改变调用它的元素,因此可以安全地链式调用其他 Cypress 命令,而不必担心会影响后续的命令。

三、.eq( )

1、语法

.eq(index)
.eq(indexFromEnd)
.eq(index, options)
.eq(indexFromEnd, options)

2、用法

正确用法;

cy.get('tbody>tr').eq(0) // Yield first 'tr' in 'tbody'
cy.get('ul>li').eq(4) // Yield fifth 'li' in 'ul'

错误用法:

cy.eq(0) // Errors, cannot be chained off 'cy'
cy.getCookies().eq(4) // Errors, 'getCookies' does not yield DOM element

3、参数

3.1、index (Number)

一个数字,表示要在元素数组中查找的元素的索引位置。索引从0开始计数。

3.2、indexFromEnd (Number)

一个负数,表示要在元素数组中从后往前查找的元素的索引位置。例如,-1表示查找最后一个元素,-2表示查找倒数第二个元素,以此类推。

3.3、options (Object)

一个对象,可以传递选项参数来更改.eq()命令的默认行为。这个对象可以包含以下属性:

  • log: 控制是否在控制台输出日志,默认为true
  • timeout: 设置命令超时时间,单位为毫秒,默认为defaultCommandTimeout

4、返回值

        .eq()方法返回的是在一组匹配元素中,选取一个特定的元素,它会返回所匹配到的新的DOM元素对象。而且,.eq()方法是一个查询方法,可以将它与其他Cypress命令链式调用,来对该DOM元素进行进一步的操作。这个DOM元素对象可以作为后续命令链的主体对象,继续使用Cypress命令进行操作。

四、.find( )

        该命令用于获取特定选择器的后代 DOM 元素。

        这个命令的查询行为与 jQuery 的 .find() 方法完全匹配。

在 jQuery 中,.find() 方法用于选择指定选择器的后代元素。它从当前元素开始,在其后代元素中进行查找,并返回匹配选择器的元素集合。这意味着它可以通过嵌套选择器来查找更具体的元素。

        在 Cypress 中,.find() 命令与 jQuery 的 .find() 方法的行为完全相同。它使用相同的查询逻辑,可以按照给定的选择器从当前选中的元素中查找后代元素。

1、语法

.find(selector)
.find(selector, options)

2、用法

正确用法:

cy.get('.article').find('footer') // Yield 'footer' within '.article'

错误用法:

cy.find('.progress') // Errors, cannot be chained off 'cy'
cy.exec('node start').find() // Errors, 'exec' does not yield DOM element

3、参数

3.1、selector (String selector)

3.2、options (Object)

4、返回值

.find() 方法在找到的新 DOM 元素上生成(yield)新的 DOM 元素。

这意味着,当使用 .find() 方法查找后代元素时,它将返回一个新的 Cypress 主体(subject),该主体包含了找到的元素集合。这使得可以在找到的元素上进一步链式调用其他 Cypress 命令。

.find() 方法本质上是一个查询方法,它执行查询操作,并返回匹配选择器的元素集合。它不会改变原始的主体(subject),而是基于原始的主体进行查询并返回新的主体,其中包含符合条件的后代元素。

因此,由于 .find() 方法返回的是新的主体,它是安全的可以在其后进行进一步的链式调用。

cy.get('.parent-element')
  .find('.child-element')
  .click()
  .should('have.class', 'active')

        在上述示例中,首先使用 .get('.parent-element') 选择器获取具有 .parent-element 类的父元素。然后,使用 .find('.child-element') 方法在父元素的后代元素中查找具有 .child-element 类的子元素。接下来,使用 .click() 方法在找到的子元素上执行点击操作。最后,使用 .should('have.class', 'active') 链式调用来断言找到的子元素是否具有 active 类。

        由于 .find() 方法返回的是新的主体,因此我们可以安全地在后续的命令中继续使用找到的元素,并对其进行操作或断言。

        通过使用 .find() 方法,我们可以按需定位并操作需要的后代元素,并在链式调用中继续进行其他操作,以便进行更复杂的测试和交互。

五、cy.window( )

用于获取当前活动页面的窗口对象(window object)

1、语法

cy.window()
cy.window(options)

2、用法

cy.window() 是 Cypress 提供的一个命令,用于获取当前活动页面的窗口对象(window object)。

        在浏览器中,window 对象代表了当前浏览器窗口或标签页。它提供了访问和操作页面的各种属性、方法和事件的接口。

        通过使用 cy.window() 命令,可以获取到当前活动页面的 window 对象,以便在测试中执行与页面窗口相关的操作和断言。

一些常见的用法示例包括:

cy.window().then((win) => {
  // 在 window 对象上执行操作或断言
  win.scrollTo(0, 500)
  expect(win.location.href).to.include('/dashboard')
})

        在上述示例中,使用 cy.window() 获取当前页面的 window 对象,并通过 .then() 方法传递给回调函数。在回调函数中,我们可以对 window 对象执行各种操作,例如调用 scrollTo() 方法滚动页面,或使用断言检查 location.href 属性是否包含指定的路径。

        通过获取 window 对象,可以在 Cypress 测试中与页面进行更高级的交互,并验证页面的行为和状态。

3、参数

3.1、options (Object)

options 对象具有以下选项:

  1. log(默认值:true):该选项用于控制是否在 Cypress 的命令日志中显示 cy.window() 命令。如果将其设置为 false,则命令将不会在日志中显示。

  2. timeout(默认值:defaultCommandTimeout):该选项用于设置等待 cy.window() 命令解析完成的超时时间。如果命令在超时时间内无法完成,Cypress 将会抛出超时错误。默认情况下,超时时间与 Cypress 的 defaultCommandTimeout 设置相同。

可以使用以下方式来使用 options 对象:

cy.window({
  log: false,
  timeout: 5000
})

        在上述示例中,我们传递了一个包含 logtimeout 属性的 options 对象给 cy.window() 命令。这将禁止在日志中显示该命令,并将超时时间设置为 5000 毫秒。

        通过使用 options 对象,可以根据需要修改 cy.window() 命令的默认行为,例如调整日志输出或更改超时时间,以适应不同的测试需求。

4、返回值

cy.window() 返回的是窗口对象(window object)。

在 Cypress 中,cy.window() 是一个查询命令,用于获取当前活动页面的窗口对象。它会将窗口对象作为主题(subject)传递给下一个命令,因此可以安全地在其后链式调用其他命令。

具体来说:

  1. cy.window() 返回的窗口对象是当前页面的 window 对象,它提供了访问和操作页面的各种属性、方法和事件的接口。

  2. 通过将 cy.window() 作为起点,可以在其后链式调用其他 Cypress 命令来操作窗口对象和执行其他断言。

下面是一个示例,展示了如何在 cy.window() 后面链式调用其他命令:

cy.window().then((win) => {
  // 在窗口对象上调用方法
  win.scrollTo(0, 500)
}).get('.element')
  .should('be.visible')
  .click()

        在上述示例中,首先使用 cy.window() 获取窗口对象,然后通过 .then() 方法传递给回调函数。在回调函数中,我们可以在窗口对象上调用方法,例如 scrollTo() 来滚动页面。

        随后,通过链式调用 .get().should().click() 等命令,可以在窗口对象的上下文中继续操作页面的其他元素。

        总结起来,cy.window() 是一个查询命令,它返回当前活动页面的窗口对象,并且可以在其后安全地链式调用其他命令来操作窗口对象和执行断言。

5、常用window对象方法

5.1、window.eval()

window.eval() 是 JavaScript 中的一个全局函数,用于将传入的字符串作为 JavaScript 代码进行解析和执行。

具体来说,window.eval() 函数接受一个参数,即要执行的 JavaScript 代码的字符串表示形式。它会将该字符串代码作为动态脚本进行解析,并在当前的全局作用域中执行。

以下是 window.eval() 的详细说明:

  • 参数:要执行的 JavaScript 代码的字符串表示形式。
  • 返回值:window.eval() 函数的返回值是被执行的代码的返回值,如果代码没有返回值,则返回 undefined
  • 执行环境:window.eval() 在全局作用域中执行代码。它可以访问全局变量、全局函数和全局对象。

使用 window.eval() 可以实现动态执行 JavaScript 代码的功能。但是需要注意的是,window.eval() 的使用应谨慎,因为它执行的代码可能会有安全风险和性能问题。

以下是一个示例,展示了如何使用 window.eval() 执行动态的 JavaScript 代码:

const code = "console.log('Hello, World!');";
window.eval(code); // 输出 "Hello, World!"

        在上述示例中,我们定义了一个字符串变量 code,其中包含要执行的 JavaScript 代码。然后,通过调用 window.eval(code),将字符串代码解析为实际的 JavaScript 代码,并在全局作用域中执行。在这个例子中,代码打印了 "Hello, World!" 到控制台。

        需要注意的是,由于 window.eval() 执行的是动态代码,因此需要格外小心,确保传入的代码是可信的,以避免可能的安全漏洞。在大多数情况下,最好考虑使用其他更安全和可控的方式来实现所需的功能。

六、.as( )

1、语法

.as(aliasName)
.as(aliasName, options)

2、用法

"为以后使用分配一个别名。在 cy.get() 查询或 cy.wait() 命令中使用 @ 前缀引用别名。

注意:.as() 假定您已经熟悉核心概念,如别名。"

        这句话的意思是,在 Cypress 中使用 .as() 方法可以为特定的命令或元素分配一个别名,以便以后引用它。在其他命令中,可以使用带有 @ 前缀的别名进行引用。

        在 Cypress 中,别名用于存储特定命令或元素的值或引用,允许您在测试中重用它们。使用 .as() 方法可以为命令或元素分配一个别名。一旦分配了别名,您可以在其他 Cypress 命令中使用带有 @ 前缀的方式来引用它。

举个例子,假设您有一个登录表单,希望为输入字段分配一个别名以便以后使用。可以这样做:

cy.get('input[name="username"]').as('usernameInput');

        在上面的代码中,cy.get() 命令选择具有名称属性 "username" 的输入字段,并使用 .as('usernameInput') 为该输入字段分配了别名 "usernameInput"。

        在测试的后续部分,您可以在其他命令中引用该别名。例如,如果您想向输入字段中输入用户名,可以使用别名如下:

cy.get('@usernameInput').type('myUsername');

        在上面的代码中,cy.get('@usernameInput') 使用别名引用了之前分配的输入字段,并通过 .type('myUsername') 在输入字段中键入用户名。

        通过使用别名,您可以在测试中轻松地引用和操作命令或元素,提高代码的可读性和可维护性。

3、参数

3.1、aliasName (String)

要在以后的 cy.get()cy.wait() 命令中使用 @ 前缀引用的别名的名称。

3.2、 options (Object)

传递一个选项对象来改变 .as() 方法的默认行为。

选项对象包含以下属性:

  • type (字符串,默认值为 "query"):指定要存储的别名类型,它会影响以后在测试中如何检索该值。有效值为 "query" 和 "static"。"query" 类型的别名每次请求别名时都会重新运行到结果值的所有查询。"static" 类型的别名在存储别名时只被检索一次,并且永远不会更改。当别名用于拦截、监视和存根时,type 属性没有影响。

        使用 as() 方法时,可以通过 options 参数来自定义别名的行为。例如,可以将别名类型设置为 "static",以便仅在存储别名时检索一次值,而不需要每次请求别名时重新运行查询。

以下是一个示例,展示了如何在使用别名时传递选项对象:

cy.get('input[name="username"]').as('usernameInput', { type: 'static' });

        在上面的代码中,使用了 { type: 'static' } 选项将别名类型设置为 "static",这意味着别名的值将在存储时被检索一次,并且不会更改。在后续的测试中,可以通过 @usernameInput 引用该别名。

通过使用选项对象,您可以根据需要自定义别名的行为,以满足测试的具体需求。

4、返回值

  • .as() 方法会产生与其给定的主题相同的结果。 在 .as() 方法之后,可以安全地链式调用其他命令。
  • .as() 方法用于为命令分配别名,并将结果传递给后续的命令。这意味着别名之后的命令可以继续操作相同的主题对象,而不会受到别名的影响。

例如,假设有以下代码:

cy.get('button')
  .as('myButton')
  .click();

        在上述代码中,cy.get('button') 选择一个按钮元素,并使用 .as('myButton') 为该按钮分配别名 "myButton"。然后,.click() 命令被链式调用,点击该按钮。

        在这个例子中,.click() 命令仍然作用于最初选择的按钮元素,即使在别名之后。这是因为 .as() 方法会返回与其给定的主题相同的主题对象,使得后续的命令可以继续操作相同的主题。

        因此,可以放心地在 .as() 方法之后链式调用其他命令,这些命令将继续操作之前选择的主题对象,而不会受到别名的干扰。这种设计使得测试代码更加清晰和可读,可以顺利地对同一个主题对象执行多个连续的操作。

七、.contains( )

Get the DOM element containing the text 表示获取包含指定文本的 DOM 元素。在页面上可能会有多个元素包含相同的文本内容,Cypress 会选择其中一个元素作为匹配结果。此外,Cypress 还会优先选择某些 DOM 元素而不是最深层次的元素。

Cypress 在执行文本匹配时,会使用一些策略来确定匹配的 DOM 元素。这些策略包括:

  1. 首选可见元素:Cypress 倾向于选择可见的元素作为匹配结果。因此,如果有多个元素包含相同的文本内容,但其中一个元素是隐藏的,Cypress 会优先选择可见元素。

  2. 选择最近的父元素:当页面上有多个元素包含相同的文本时,Cypress 会选择最近的父元素作为匹配结果。这样可以确保获取的元素与期望的元素更接近。

  3. 多个匹配元素:如果有多个元素包含相同的文本内容且满足匹配条件,Cypress 会返回其中一个匹配的元素作为结果。具体选择哪个元素可能是不确定的,取决于 Cypress 的实现和算法。

        需要注意的是,虽然 Cypress 会尽可能选择合适的元素作为匹配结果,但仍然可能存在一些误差或不确定性。因此,在编写测试脚本时,建议尽量使用更具体的选择器或结合其他条件来精确定位目标元素,以确保获取到正确的 DOM 元素。

1、语法

.contains(content)
.contains(content, options)
.contains(selector, content)
.contains(selector, content, options)

// ---or---

cy.contains(content)
cy.contains(content, options)
cy.contains(selector, content)
cy.contains(selector, content, options)

2、用法

假设我们有以下 HTML 结构:

<div class="container">
  <h1>Hello World</h1>
  <p>This is a paragraph.</p>
</div>

        我们可以使用 cy.contains() 方法来查找包含指定文本的元素。例如,我们要找到包含文本 "Hello World" 的 <h1> 元素:

cy.contains('Hello World')  // 匹配 <h1>Hello World</h1> 元素

        如果我们只想在特定的元素范围内查找,可以将选择器或 DOM 元素作为第一个参数传递给 cy.contains() 方法。例如,我们只想在 .container 元素内查找包含文本 "Hello World" 的元素:

cy.get('.container').contains('Hello World')  // 匹配 <h1>Hello World</h1> 元素

         此外,我们还可以使用选项对象来进一步配置 cy.contains() 方法的行为。例如,我们可以指定超时时间为 5000 毫秒:

cy.contains('Hello World', { timeout: 5000 })

        总结一下,cy.contains() 方法允许我们根据指定的文本内容在页面上查找匹配的 DOM 元素。我们可以通过选择器、元素范围和选项对象来更精确地定位目标元素。这样,我们就可以方便地对找到的元素执行其他 Cypress 命令和断言。

3、参数

3.1、content (String, Number, RegExp)

(字符串、数字、正则表达式):要查找的文本内容。

3.2、selector (String selector)

(字符串选择器):指定一个选择器来过滤包含文本的 DOM 元素。Cypress 将忽略对选择器的默认偏好顺序。使用选择器可以返回包含指定文本的更浅的元素(在树中较高的位置)。

3.3、options (Object)

可以传递一个选项对象来改变 .contains() 方法的默认行为。

选项对象中的可用选项有:

  • matchCase(布尔值,默认为 true):检查大小写敏感性。
  • log(布尔值,默认为 true):在命令日志中显示该命令。
  • timeout(数值,默认为 defaultCommandTimeout):等待 .contains() 解析的时间,超时前等待。
  • includeShadowDom(布尔值,默认为 includeShadowDom 配置选项的值):是否遍历阴影 DOM 边界并包含阴影 DOM 内的元素在返回结果中。

        通过上述参数,我们可以根据指定的文本内容和选择器在页面上查找匹配的 DOM 元素,并可以通过选项对象来自定义行为。这样,我们就可以更灵活地使用 .contains() 方法来定位元素并进行相关操作。

4、返回值

.contains() 方法返回找到的新的 DOM 元素。

.contains() 是一个查询操作,因此可以在其后安全地链式调用其他命令。

        这意味着,当使用 .contains() 方法查找到匹配的 DOM 元素后,你可以继续在该元素上执行其他 Cypress 命令,例如 .click().type() 等,以便进一步与该元素进行交互或执行其他操作。通过链式调用命令,你可以顺序执行一系列操作,以实现所需的测试行为或断言。

八、.parents( )

1、在 Cypress 中,.parents() 是一个命令,用于获取一组 DOM 元素的父级 DOM 元素。

2、需要注意的是,.parents() 命令与 .parent() 命令有所不同。.parent() 命令只会向上遍历 DOM 树一级,而.parents() 命令会遍历多级的父级 DOM 元素。

3、该命令的查询行为与 jQuery 中的 .parents() 完全相同。

4、简而言之,.parents() 命令用于获取一组 DOM 元素的所有父级元素,而不仅限于直接父级。它会向上遍历 DOM 树,并返回匹配的父级元素集合。

1、语法

.parents()
.parents(selector)
.parents(options)
.parents(selector, options)

2、用法

正确用法:

cy.get('.child-element').parents('.parent-element').should('have.length', 2);

        在上述示例中,.parents('.parent-element') 表达式将获取所有类名为 .parent-element 的父级元素,该元素是类名为 .child-element 的元素的祖先元素。然后,使用 .should() 断言,验证匹配的父级元素数量为 2。

        因此,通过使用 .parents() 命令,您可以获取一组 DOM 元素的所有父级元素,并对它们执行进一步的操作和断言。

cy.get('.child-element').parents('.parent-element', { log: false, timeout: 5000 })

        在上述示例中,.parents('.parent-element', { log: false, timeout: 5000 }) 表达式将获取类名为 .child-element 的元素的所有父级元素,并且只返回匹配选择器 .parent-element 的父级元素。此外,通过选项参数,命令的日志记录将被禁用,超时时间设置为 5000 毫秒。

        因此,通过使用参数,您可以根据需要对 .parents() 命令进行自定义配置,以满足不同的测试需求。

错误用法:

cy.parents() // Errors, cannot be chained off 'cy'
cy.clock().parents() // Errors, 'clock' does not yield DOM elements

3、参数

3.1、selector (String selector)

        用于过滤匹配的 DOM 元素的选择器。通过提供选择器,您可以指定要获取父级元素的特定条件。只有匹配选择器的父级元素会被返回。

3.2、options (Object)

可以传递一个选项对象来改变 .parents() 命令的默认行为。

  • log(默认值为 true):控制是否在命令日志中显示该命令的记录。如果设置为 false,则该命令不会在命令日志中显示。
  • timeout(默认值为 defaultCommandTimeout):设置等待 .parents() 命令执行完成的超时时间。如果命令执行时间超过该时间限制,将导致超时错误。

        通过使用这些参数,您可以对 .parents() 命令进行进一步的定制,以满足特定的需求。例如,您可以使用选择器参数来过滤要获取的父级元素,或者使用选项参数来调整命令的日志记录和超时时间。

4、返回值

.parents() 命令返回它找到的新的 DOM 元素(或元素集合)。

        这意味着当您使用 .parents() 命令时,它会返回符合选择条件的父级 DOM 元素,并将其作为 Cypress 主体对象(subject)提供给后续的命令。

        通过这个特性,您可以在 .parents() 命令后面链式调用其他 Cypress 命令,以进一步操作或断言返回的父级元素。

以下是一些示例说明:

cy.get('.child-element')
  .parents('.parent-element')
  .should('have.class', 'parent-element')
  .and('have.length', 2)
  .each(($parentElement) => {
    // 在每个父级元素上执行进一步的操作
    cy.wrap($parentElement).contains('Some text');
  });

        在上述示例中,首先使用 .get('.child-element') 命令获取类名为 .child-element 的元素。然后,使用 .parents('.parent-element') 命令获取所有符合选择器 .parent-element 的父级元素。

        接下来,通过链式调用 .should() 命令进行断言,验证返回的父级元素具有特定的类名和数量。

        最后,通过 .each(($parentElement) => { ... }) 命令,对每个父级元素执行回调函数,并在回调函数中使用 cy.wrap($parentElement) 来包装父级元素,以便可以在其上执行进一步的操作,比如使用 .contains() 命令查找包含特定文本的子元素。

        因此,通过使用 .parents() 命令返回的父级元素,您可以继续链式调用其他 Cypress 命令,以对这些元素执行更多的操作和断言。这样,您可以构建出更复杂的测试场景。

第三章、Actions

一、Actions API 共性

1、返回相同的subject

        在 Cypress 中,每个命令都有一个“主体”(subject),指代当前被操作的元素或对象。例如,cy.get() 命令的主体就是获取到的 DOM 元素。在这种情况下,".click()" 命令会针对这个 DOM 元素执行点击操作,并且它的返回值依然是这个 DOM 元素,也就是说,它“产生”的主体与输入主体相同。因此,".click()" 命令的这句话的意思就是:它的输出主体和输入主体是一致的,即它执行完点击操作后仍然是当前的 DOM 元素。

2、Action执行后不可链接其他命令

It is unsafe to chain further commands that rely on the subject after .click().

        这句话的意思是,在使用 .click() 命令之后,不能再链式调用其他的命令来操作同一个元素,因为在执行 .click() 命令后,被点击的元素可能会发生变化,如果继续在同一个元素上进行其他操作,就有可能操作到了一个已经变化的元素,导致测试结果不准确。因此,建议在使用 .click() 命令后,将被点击的元素重新选取并赋值给一个新的变量,再用这个变量进行后续操作。

将被点击的元素重新选取并赋值给一个新的变量,可以使用以下方法:

cy.get('button').then($button => {
  const buttonText = $button.text() // 获取按钮上的文本
  cy.wrap($button).click() // 点击按钮
  cy.get('p').contains(buttonText) // 获取包含按钮文本的段落元素
})

        在这个例子中,我们首先使用 cy.get() 获取一个按钮元素,并将其赋值给 $button 变量。接下来,我们可以使用 $button 变量来操作按钮元素。在这里,我们使用 $button.text() 获取按钮上的文本,然后点击按钮。然后,我们使用 cy.get() 重新选择页面上的段落元素,并使用 contains() 方法查找包含按钮文本的元素。由于我们已经有了按钮文本,所以我们可以轻松地在包含按钮文本的元素中找到它。这样,我们就能够在点击按钮之后继续操作其他元素了。

        由于 .click() 方法会触发一次实际的 DOM 点击事件,可能会导致一些副作用,比如页面跳转或者弹出新窗口等,因此 Cypress 在 .click() 后不再保证原来的选取元素 subject 的有效性,而是建议重新选取元素并赋值给一个新的变量,然后对这个新的变量继续操作,以避免出现意料之外的问题。

二、.select( )

1、cypress命令.select()用于选择<select>元素中的<option>元素

2、如果在<select>元素中有多个相同值或文本的选项,那么cy.select()默认选择第一个匹配的选项。如果需要选择其他选项,可以使用.eq().contains()命令来定位到具体的选项。

1、语法

.select(value)
.select(values)
.select(value, options)
.select(values, options)

2、用法

举个例子,如果我们有如下的HTML代码:

<select>
  <option value="1">Option 1</option>
  <option value="2">Option 2</option>
  <option value="3">Option 3</option>
</select>

那么如果我们想要选择第二个<option>元素,可以使用以下代码:

cy.get('select').select(1)

 或者

cy.get('select').select('Option 2')

如果我们想要选择第一个和第三个<option>元素,可以使用以下代码:

cy.get('select').select(['Option 1', 'Option 3'])

3、参数

3.1、value (String, Number)

        接受一个字符串或数字作为参数,表示要选择的<option>元素的value属性值、index属性值或者文本内容。

3.2、values (Array)

        接受一个数组作为参数,每个元素可以是字符串或数字,表示要选择的<option>元素的value属性值、index属性值或者文本内容。当选择多个<option>元素时,可以使用这个参数。

3.3、options (Object)

  • {force: true}:强制选择选项,即使该选项被隐藏或禁用。
  • {timeout: timeoutValue}:设置命令超时时间,单位为毫秒。
  • {log: false}:禁用该命令的日志输出。

4、返回值

        在 .select() 命令之后,它会返回相同的主体对象(也就是被选中的 <select> 元素),因此不应该继续在它之后进行依赖于主体对象的命令,因为它们可能无法正确处理所期望的值或状态。如果需要在 .select() 之后执行其他命令,则应该使用 .then() 命令将命令封装到回调函数中。

三、.click( )

点击一个 DOM 元素。

在使用 .click() 方法后,不安全地继续链式调用依赖于该元素的其他命令。

.click() 方法用于模拟点击 DOM 元素的操作。它触发元素的点击事件,可以模拟用户点击按钮或链接等交互操作。

1、语法

.click()
.click(options)
.click(position)
.click(position, options)
.click(x, y)
.click(x, y, options)

2、用法

正确用法:

cy.get('.btn').click() // Click on button
cy.focused().click() // Click on el with focus
cy.contains('Welcome').click() // Click on first el containing 'Welcome'

错误用法:

cy.click('.btn') // Errors, cannot be chained off 'cy'
cy.window().click() // Errors, 'window' does not yield DOM element

3、参数

3.1、position (String)

        指定点击的位置。默认情况下,点击位置是居中的。有效的位置包括:topLeft、top、topRight、left、center、right、bottomLeft、bottom 和 bottomRight。

3.2、x (Number)

距离元素左侧的像素距离,用于指定点击的位置。

3.3、y (Number)

距离元素顶部的像素距离,用于指定点击的位置。

3.4、options (Object)

传入一个选项对象以改变 .click() 的默认行为。

选项包括:

  • altKey:是否激活 Alt 键(对于 Mac 是 Option 键)。别名:optionKey。
  • animationDistanceThreshold:动画距离阈值,以像素为单位,用于判断元素是否处于动画中。
  • ctrlKey:是否激活 Ctrl 键。别名:controlKey。
  • log:是否在命令日志中显示该命令。
  • force:是否强制执行点击操作,禁用等待可操作性。
  • metaKey:是否激活 Meta 键(对于 Mac 是 Command 键)。别名:commandKey、cmdKey。
  • multiple:是否连续点击多个元素。
  • scrollBehavior:执行命令之前,元素应滚动到的视口位置。
  • shiftKey:是否激活 Shift 键。
  • timeout:等待 .click() 完成的超时时间。
  • waitForAnimations:是否等待元素完成动画后再执行命令。

通过传入这些选项对象,可以改变 .click() 方法的默认行为,以满足特定的需求。

 

4、返回值

.click() 方法返回与之前给定的主体相同的主体。这意味着它不会返回一个新的主体,而是保持原来的主体不变。

        在使用 .click() 方法后,不安全继续链式调用依赖于主体的其他命令。这是因为 .click() 方法会触发实际的点击操作,可能导致页面的变化或跳转,从而导致后续命令无法在预期的元素上执行。

        需要注意的是,在调用 .click() 方法后,不建议继续链式调用依赖于该元素的其他命令,也就是在点击之后不要再进行进一步的操作。这是因为点击事件可能会导致页面的变化或导航,而此时该元素可能已经不再可用或处于预期的状态。

        如果需要在点击之后执行额外的操作,建议将它们分为独立的命令。例如,可以使用 .then() 方法将后续的命令链接到点击操作之后:

cy.get('.my-button').click().then(() => {
  // 在这里执行额外的操作
  cy.get('.my-element').should('be.visible');
});

通过使用 .then(),确保在点击完成后执行后续的命令。

需要注意的是,Cypress 的命令是异步执行并以可链接的方式操作,因此每个命令会按顺序执行。

5、点击异常情况

情况一:

        元素虽然可见,但可能被其他元素覆盖导致无法触发点击。您可以尝试使用 { force: true } 参数来强制执行点击操作。

cy.get('.home-menu-trigger').should('be.visible').click({ force: true })

情况二:

        页面中的某些异步操作或动画导致点击操作不稳定。您可以尝试添加适当的等待时间,或使用 cy.wait() 命令确保元素完全加载和可点击后再执行点击操作。

cy.get('.home-menu-trigger').should('be.visible').wait(1000).click();

请注意,在进行强制点击或添加等待时间时,需要确保元素的可见性和可点击性已经验证过。

情况三:

直接操作DOM元素对象

cy.get('.home-menu-trigger').then(($button) => {
  $button[0].click(); // 或者 $button.get(0).click();
});

        请注意,访问原生 DOM 元素可能会绕过 Cypress 的事件模拟和自动等待功能,因此需要确保元素在可见、可交互的状态下才进行点击操作。

四、.type( )

.type() 方法用于向 DOM 元素输入文本内容。

在使用 .type() 方法后,不安全继续链式调用依赖于主体的其他命令。这是因为 .type() 方法会模拟键盘输入操作,可能导致页面的变化或触发事件,从而影响后续命令的执行。

1、语法

.type(text)
.type(text, options)

2、用法

输入文本:

cy.get('input').type('Hello, World!')

清空输入框并输入文本:

cy.get('input').clear().type('Hello, World!')

模拟按键操作:

cy.get('input').type('{enter}')  // 模拟按下 Enter 键
cy.get('input').type('{ctrl}a')  // 模拟按下 Ctrl+A 键

速度控制:

cy.get('input').type('Hello, World!', { delay: 100 })  // 每个字符之间的输入间隔为 100 毫秒

强制输入:

cy.get('input').type('Hello, World!', { force: true })  // 忽略输入框是否可见或可操作性,强制输入文本

3、参数

3.1、text (String)

要输入到 DOM 元素中的文本内容。

        在 .type() 方法中传递的文本内容可以包含以下特殊字符序列。这些字符序列将正确地传递给事件的 keyCode、key 和 which 属性。其中一些特殊字符序列在键入过程中执行特定的操作,例如 {moveToEnd}{moveToStart}{selectAll}

如果要禁用特殊字符序列的解析,请将 parseSpecialCharSequences 选项设置为 false

特殊字符序列说明如下:

  • {{}:输入字面的 { 键。
  • {backspace}:删除光标左侧的字符。
  • {del}:删除光标右侧的字符。
  • {downArrow}:将光标向下移动。
  • {end}:将光标移动到行的末尾。
  • {enter}:输入回车键。
  • {esc}:输入 Escape 键。
  • {home}:将光标移动到行的开头。
  • {insert}:在光标右侧插入字符。
  • {leftArrow}:将光标向左移动。
  • {moveToEnd}:将光标移动到可输入元素的末尾。
  • {moveToStart}:将光标移动到可输入元素的开头。
  • {pageDown}:向下滚动。
  • {pageUp}:向上滚动。
  • {rightArrow}:将光标向右移动。
  • {selectAll}:通过创建选择范围来选择所有文本。
  • {upArrow}:将光标向上移动。

此外,可以在 .type() 方法中包含任何这些修饰符字符序列:

  • {alt}:激活 altKey 修饰符。别名:{option}
  • {ctrl}:激活 ctrlKey 修饰符。别名:{control}
  • {meta}:激活 metaKey 修饰符。别名:{command}{cmd}
  • {shift}:激活 shiftKey 修饰符。

3.2、options (Object)

通过传递一个选项对象来修改 .type() 方法的默认行为,可用的选项如下:

请注意,.type() 方法会返回与传入的主体相同的主体,并且在 .type() 方法后面不安全地链式调用依赖于主体的进一步命令。这是因为在 .type() 方法后,元素的状态可能会发生变化,进而导致后续的命令失败。

  • animationDistanceThreshold:动画距离阈值(像素),元素必须超过该阈值才被视为正在执行动画。
  • delay:每次按键后的延迟时间(毫秒)。
  • force:强制执行操作,禁用等待元素可操作性的操作。
  • log:是否在命令日志中显示该命令。
  • parseSpecialCharSequences:解析字符串中使用 { } 包围的特殊字符序列,默认为 true。如果设置为 false,将输入字面字符而不是特殊字符序列。
  • release:在命令之间保持修饰符的激活状态。
  • scrollBehavior:执行命令前应滚动到的视口位置。
  • timeout:等待 .type() 方法解析完成的超时时间。
  • waitForAnimations:在执行命令前是否等待元素完成动画效果。

4、返回值

.type() 方法返回与其给定的主题(即表单字段)相同的对象

        这意味着 .type() 方法将在执行输入操作后返回原始的主题,以便可以进一步链式调用其他命令。但是,给出的警告 "It is unsafe to chain further commands that rely on the subject after .type()" 意味着在 .type() 方法之后,依赖于主题的进一步命令的链式调用是不安全的。

        这是因为 .type() 方法触发了一系列的事件,例如 keydownkeypressinput。这些事件通常会导致页面的重新渲染或触发其他异步操作。如果在这些异步操作未完成之前立即链式调用其他命令,可能会导致测试出现不稳定的结果。

        为了确保稳定性和可预测性,建议在使用 .type() 方法后使用 .should().then() 等断言方法来验证输入是否已成功,或者在链式调用之前添加适当的等待操作(例如 cy.wait()),以确保异步操作完成。这样可以避免在输入操作完成之前对主题进行进一步的命令操作。

五、.check( )

.check() 是 Cypress 中的一个命令,用于选中(勾选)复选框或单选按钮。

        该命令用于操作 <input> 元素,并将其选中状态设置为选中(checked)状态。但需要注意的是,在使用 .check() 命令后,不安全(unsafe)继续链式调用其他依赖于主体的命令。

.check() 命令要求元素必须是 <input> 元素,并且具有 type 属性为 checkbox 或 radio。否则,该命令将无效。

1、语法

.check()
.check(value)
.check(values)
.check(options)
.check(value, options)
.check(values, options)

2、用法

正确用法:

cy.get('.checkbox-input').check();
cy.get('.radio-input').check('option-2');

        在上述示例中,.check() 命令用于选中具有类名为 .checkbox-input 的复选框,并将其状态设置为选中。

        第二个示例中,.check('option-2') 命令用于选中类名为 .radio-input 的单选按钮组中的第二个选项。

        需要注意的是,在使用 .check() 命令后,不安全(unsafe)继续链式调用其他依赖于主体的命令。这是因为 .check() 命令操作的是一个原生的 <input> 元素,而不是 Cypress 的主体对象。因此,如果在 .check() 后继续使用依赖于主体对象的命令,可能会导致意料之外的行为或错误。

        如果需要在 .check() 后执行进一步的操作,建议使用 .then() 命令来处理。例如:

cy.get('.checkbox-input').check().then(($input) => {
  // 在这里可以使用 $input 执行进一步的操作
  // 例如验证选中状态或获取其他属性值
});

        在上述示例中,使用 .then() 命令获取 .check() 命令的结果,并在回调函数中处理进一步的操作。

        总之,.check() 命令用于选中复选框或单选按钮,并且在使用后应谨慎处理后续的命令,以避免不安全的链式调用。

cy.get('.checkbox-input').check('value-1', { log: false, timeout: 5000 });
cy.get('.checkbox-input').check(['value-1', 'value-2'], { force: true });

        在上述示例中,.check('value-1', { log: false, timeout: 5000 }) 命令用于选择值为 'value-1' 的复选框,禁用了命令的日志记录,并设置了超时时间为 5000 毫秒。

        第二个示例中,.check(['value-1', 'value-2'], { force: true }) 命令用于选择值为 'value-1''value-2' 的多个复选框,并强制执行操作,即禁用等待元素可操作性的等待过程。

        通过使用这些参数,您可以根据需要对 .check() 命令进行自定义配置,以满足不同的测试场景需求。

错误用法:

cy.check('[type="checkbox"]') // Errors, cannot be chained off 'cy'
cy.get('p:first').check() // Errors, '.get()' does not yield checkbox or radio

3、参数

3.1、value (String)

        要选中的复选框或单选按钮的值(value)。通过指定值,您可以选择具有特定值的复选框或单选按钮。

3.2、values (Array)

        要选中的复选框或单选按钮的值(value)的数组。通过提供值的数组,您可以同时选择多个复选框或单选按钮。

3.3、options (Object)

可以传递一个选项对象来改变 .check() 命令的默认行为。

  • animationDistanceThreshold(默认值为 animationDistanceThreshold):元素在一段时间内必须超过的像素距离,才被视为正在执行动画。
  • log(默认值为 true):控制是否在命令日志中显示该命令的记录。如果设置为 false,则该命令不会在命令日志中显示。
  • force(默认值为 false):强制执行操作,禁用等待元素可操作性的等待过程。
  • scrollBehavior(默认值为 scrollBehavior):执行命令前将元素滚动到的视口位置。
  • timeout(默认值为 defaultCommandTimeout):设置等待 .check() 命令执行完成的超时时间。如果命令执行时间超过该时间限制,将导致超时错误。
  • waitForAnimations(默认值为 waitForAnimations):在执行命令之前是否等待元素完成动画。

        通过使用这些参数,您可以更改 .check() 命令的行为,以满足特定的测试需求。例如,通过指定特定的值或值的数组,您可以选择特定的复选框或单选按钮。您还可以调整日志记录、超时时间以及其他行为选项。

4、返回值

.check() 命令返回与其输入相同的主体对象(subject)。

        这意味着,当您使用 .check() 命令时,它会返回与之前相同的主体对象,而不会更改主体对象的引用。

        然而,需要注意的是,在使用 .check() 命令后,不安全(unsafe)继续链式调用其他依赖于主体对象的命令。

        这是因为 .check() 命令操作的是原生的 <input> 元素,而不是 Cypress 的主体对象。因此,如果在 .check() 后继续使用依赖于主体对象的命令,可能会导致意料之外的行为或错误。

为了避免此类问题,建议在需要进一步操作主体对象时,使用 .then() 命令来处理。例如

cy.get('.checkbox-input').check().then(($input) => {
  // 在这里可以使用 $input 执行进一步的操作
  // 例如验证选中状态或获取其他属性值
});

        在上述示例中,使用 .then() 命令获取 .check() 命令的结果,并在回调函数中处理进一步的操作。通过这种方式,您可以安全地操作主体对象,而不会受到 .check() 命令的限制。

        总之,.check() 命令会返回与输入相同的主体对象,但在使用后不安全(unsafe)继续链式调用其他依赖于主体对象的命令。为了安全地操作主体对象,建议使用 .then() 命令来处理后续操作。

第四章、Other Commands

一、cy.visit()

1、语法

cy.visit(url)
cy.visit(url, options)
cy.visit(options)

2、用法

cy.visit('/') // visits the baseUrl
cy.visit('index.html') // visits the local file "index.html" if baseUrl is null
cy.visit('http://localhost:3000') // specify full URL if baseUrl is null or the domain is different the baseUrl
cy.visit({
  url: '/pages/hello.html',
  method: 'GET',
})

        在 Cypress 中,cy.visit() 命令可以同时接受 URL 和选项对象作为参数,因此可以同时使用。以下是使用 cy.visit() 命令同时传递 URL 和选项对象的示例:

cy.visit('https://www.example.com', {
  timeout: 10000,
  onBeforeLoad: (win) => {
    // Custom handling before the page loads
  }
});

        在上面的示例中,cy.visit() 命令同时传递了 URL 和一个选项对象,该选项对象包含了一个超时时间和一个 onBeforeLoad 回调函数。

3、参数

3.1、url (String)

要访问的url地址

3.2、options (Object)

通过传入一个选项对象来控制visit() 命令的实现

默认使用pageLoadTimeout和baseUrl在配置中设置全局

 4、返回值

        在Cypress中,cy.visit()命令在页面加载完成后会返回window对象,这个对象不应该再被用于继续执行后续命令,因为这可能会导致不可预测的结果或者错误的行为。因此,如果需要在页面加载完成后执行其他命令,应该在cy.visit()命令之后使用.then()方法来链式调用后续命令,以确保这些命令在页面加载完成后执行。例如:

cy.visit('https://www.example.com')
  .then(() => {
    // 在页面加载完成后执行其他命令
    cy.get('button').click()
  })

二、cy.wrap( )

.wrap() 方法可以用于将任意对象包装为 Cypress 主题对象,使得可以在后续的命令中对该对象进行操作。如果被包装的对象是一个 Promise 对象,Cypress 会等待该 Promise 对象被解析,并将其解析值传递给后续的命令。

1、语法

cy.wrap(subject)
cy.wrap(subject, options)

2、用法

cy.wrap(someObject).then((wrappedObject) => {
  // 对 wrappedObject 进行操作
});

cy.wrap(somePromise).then((resolvedValue) => {
  // 对 resolvedValue 进行操作
});

        在上述代码中,.wrap() 方法分别用于包装 someObjectsomePromise。如果 someObject 是一个普通对象,那么 wrappedObject 将直接成为 Cypress 主题对象,可以在 .then() 回调函数中对其进行操作。如果 somePromise 是一个 Promise 对象,Cypress 会等待该 Promise 对象被解析,并将其解析值作为 resolvedValue 传递给 .then() 回调函数。

        通过使用 .wrap() 方法,可以将任意对象转换为 Cypress 主题对象,并在后续的命令中进行链式操作。这种灵活性使得可以在 Cypress 测试中处理各种类型的数据和异步操作。

3、参数

3.1、subject (Object)

一个要被转换的主体对象

3.2、options (Object)

4、返回值

        在Cypress中,.wrap()是一个可以用于将一个对象转换为Cypress包装对象的方法。该方法可以接收一个普通的JavaScript对象或一个Promise对象并返回一个Cypress命令对象,该对象具有Cypress的所有命令和函数。

        当使用.wrap()将一个普通的JavaScript对象传递给Cypress时,该对象会被包装为Cypress命令对象,并直接作为.wrap()的返回值。但如果传递的是一个Promise对象,.wrap()的返回值将是一个包装了Promise对象的Cypress对象,这意味着我们不能直接访问Promise的返回值,而需要使用.then()方法来等待Promise对象被解析后,才能获取到最终的返回值。

        在.wrap()的结果中,我们可以使用.then()方法来访问传递给.wrap()的对象或Promise对象的解析值,并将其传递给后续的命令或函数。该解析值将作为后续命令链中上一个命令的主体对象传递。如果传递给.wrap()的是一个Promise对象,那么.then()方法将在Promise对象被解析后立即执行,并将解析值作为它的参数。而如果传递给.wrap()的是一个普通的JavaScript对象,那么.then()方法将在下一次调用Cypress命令时立即执行。

        总的来说,.wrap()方法可以用于将JavaScript对象转换为Cypress对象,并允许我们使用Cypress命令对其进行操作。在使用.then()方法时,可以访问到传递给.wrap()的对象或Promise对象的解析值,并将其传递给后续的命令或函数。

5、传递subject:普通的JavaScript对象

将一个普通的JavaScript对象传递给.wrap()方法:

const obj = { name: 'Tom', age: 18 }
cy.wrap(obj)
  .should('have.property', 'name', 'Tom')
  .should('have.property', 'age', 18)

        在这个例子中,将一个普通的JavaScript对象 obj 传递给了.wrap()方法,并在后续使用Cypress命令对其进行操作。.should()命令作为后续的命令,对上一个命令的主体对象进行断言,所以在第一个.should()命令中,主体对象为 obj,断言其具有名为 name,值为 'Tom' 的属性。同理,第二个.should()命令中,主体对象为 obj,断言其具有名为 age,值为 18 的属性。

6、传递subject:promise对象

将一个Promise对象传递给.wrap()方法:

const promise = new Promise(resolve => {
  setTimeout(() => resolve('Hello, world!'), 2000)
})
cy.wrap(promise)
  .then(text => {
    cy.get('h1')
      .should('have.text', text)
  })

        在这个例子中,将一个Promise对象 promise 传递给了.wrap()方法,并使用.then()方法获取其解析值 text,然后将其作为参数传递给后续的命令链。在.then()方法中,我们使用.get()命令获取页面上的 h1 元素,并断言其文本值为 text。需要注意的是,由于传递给.wrap()的是一个Promise对象,.then()方法会在Promise对象被解析后立即执行,并将解析值作为其参数,所以此时可以直接使用解析值 text 进行后续操作。

7、传递subject:数组对象

cy.wrap() 命令可以用于包装数组,不仅仅是对象。

cy.wrap() 命令的作用是将一个值包装为 Cypress 主体对象(subject),以便在 Cypress 测试中对其进行链式操作。

当将数组传递给 cy.wrap() 命令时,它会将数组作为一个整体包装,并允许您对数组进行操作。

以下是一个示例:

const myArray = [1, 2, 3, 4, 5];

cy.wrap(myArray).each((item) => {
  // 对数组中的每个元素执行操作
  cy.log(`Item: ${item}`);
});

        在上述示例中,cy.wrap(myArray) 将数组 myArray 包装为 Cypress 主体对象,然后使用 .each() 方法对数组中的每个元素执行回调函数。在回调函数中,我们通过 cy.log() 记录了数组的每个元素。

        因此,通过使用 cy.wrap() 命令,您可以对数组执行各种 Cypress 命令和断言,以便进行测试和操作。

三、.then( )

subject为promise对象

1、语法

.then(callbackFn)
.then(options, callbackFn)

2、用法

案例一:

        在 Cypress 中,.then() 方法可以用于等待上一个 Cypress 命令执行完成后执行回调函数。.then() 方法接收一个回调函数作为参数,回调函数会在上一个 Cypress 命令执行完毕后被调用,该回调函数的参数则是上一个 Cypress 命令的返回值。

下面是一个使用 .then() 方法的示例:

cy.get('#some-input')
  .type('some text')
  .then(() => {
    // 上一个命令 cy.type('some text') 执行完毕后,执行以下回调函数
    cy.get('#some-other-input').type('some other text')
  })

        在上面的示例中,.type() 命令用于在 id 为 some-input 的输入框中输入文本。然后使用 .then() 方法,等待 .type() 命令执行完毕后,执行回调函数,该回调函数使用 .type() 命令在 id 为 some-other-input 的输入框中输入文本。

        需要注意的是,如果回调函数返回一个 Promise 对象,那么 .then() 方法会等待该 Promise 对象被解析后再继续执行后续的 Cypress 命令。下面是一个使用 .then() 方法和返回 Promise 对象的示例:

cy.get('#some-input')
  .type('some text')
  .then(() => {
    return new Promise(resolve => {
      setTimeout(() => {
        resolve()
      }, 1000)
    })
  })
  .then(() => {
    // 上一个命令 cy.type('some text') 执行完毕后,等待 1 秒后,执行以下回调函数
    cy.get('#some-other-input').type('some other text')
  })

        在上面的示例中,回调函数返回了一个 Promise 对象,该 Promise 对象会在 1 秒后被解析。因此,在第一个 .then() 方法执行完毕后,会等待 1 秒后,再执行下一个 .then() 方法。 

 案例二:

cy.get('.nav').then(($nav) => {}) // Yields .nav as first arg

        这段代码使用cy.get()命令来获取页面上所有具有.nav类名的元素,然后将这些元素作为第一个参数传递给.then()方法中的回调函数,即($nav) => {}

        在这个回调函数中,$nav变量表示被获取到的.nav元素,可以对这个元素进行一系列的操作,例如调用其他Cypress命令或者使用jQuery等库中的方法。

        需要注意的是,.then()方法中的回调函数只有在之前的命令被解析并执行完毕后才会执行,因此可以保证在回调函数中操作的元素是已经存在于DOM中的。

        在这里,"$"符号并不是JavaScript或Cypress的一个特定语法,它只是一种命名习惯,通常用于标识一个jQuery对象或包含DOM元素的对象。实际上,$只是一个有效的JavaScript变量名,并没有任何特殊含义。在这个例子中,$nav就是一个Cypress包装的jQuery对象,它包含了所有匹配".nav"选择器的DOM元素。

3、参数

3.1、options (Object)

3.2、callbackFn (Function)

        回调函数的第一个参数通常是前一个命令返回的对象,也就是被称为“主体”或“主题”的对象,后续参数则依次是后续命令返回的对象。

4、返回值

        当我们使用.then()函数时,返回值会被作为下一个Cypress命令的主题(subject)传递。如果回调函数返回了Cypress命令的链式调用或Promise,Cypress会等待它们完成,并将它们的返回值作为新的主题继续执行命令。如果回调函数返回undefined或null(或没有返回值),则上一个Cypress命令的结果将作为新的主题。如果回调函数返回undefined或null(或没有返回值),并且回调函数没有调用任何Cypress命令,则主题将不会被修改,上一个主题将继续传递到下一个命令。同时需要注意的是,.then()函数的回调函数不会被重试。如果直接返回DOM元素,而没有使用Cypress查询定位到要操作或断言的元素,那么是不安全的。

四、.each( )

        当使用 .each() 方法迭代数组或带有 length 属性的对象时,这个方法会对每个元素执行一个回调函数。在回调函数中,你可以对元素进行操作或执行其他逻辑。然而,一旦 .each() 方法被调用,它会立即迭代整个数组或对象,并且它是同步执行的,意味着它会阻塞后续代码的执行,直到迭代完成。

        由于 .each() 是同步执行的,当你在回调函数中尝试使用该数组或对象进行进一步操作时,可能会遇到问题。这是因为在迭代过程中,原始的数组或对象可能会被修改,导致后续的操作产生意外的结果或错误。

        因此,在使用 .each() 方法之后,最好避免在同一链式调用中继续使用依赖于原始数组或对象的其他命令。如果需要进一步操作或链式调用其他方法,建议在 .each() 方法之后创建一个新的链式调用或使用回调函数来处理进一步的逻辑。这样可以确保每个操作在正确的上下文中执行,避免潜在的错误或意外行为。

        总之,当你使用 .each() 方法迭代数组或对象时,请注意不要在同一链式调用中继续使用依赖于原始数组或对象的其他命令,以确保代码的正确性和可预测性。

1、语法

.each(callbackFn)

2、用法

正确用法:

cy.get('.my-list-item').each((element, index, list) => {
  cy.wrap(element).click(); // 对每个元素执行点击操作
})

        在上述示例中,.each() 方法迭代了所有具有 .my-list-item 类的元素,并在每个元素上执行点击操作。

        需要注意的是,.each() 方法是同步的,它会立即迭代整个元素集合。如果你需要进行异步操作,你可以在回调函数中使用 cy.wrap() 或其他 Cypress 命令,确保正确的命令顺序和处理。

错误用法:

cy.each(() => {...})            // Errors, cannot be chained off 'cy'
cy.clock().each(() => {...})    // Errors, 'clock' does not yield an array

3、参数

3.1、callbackFn (Function)

  • element: 当前迭代的元素。必选
  • index: 当前元素在集合中的索引。可选
  • list: 包含所有元素的集合。可选

4、返回值

        在 Cypress 中,.each() 方法的一个重要特性是它将相同的主体(subject)传递给回调函数。也就是说,无论你在 .each() 方法之前选择了什么元素作为主体,回调函数中的主体将与之相同。

        这意味着,.each() 方法不会改变主体的上下文。它只是将主体的每个元素依次传递给回调函数,让你可以对每个元素执行特定的操作。

        然而,这也意味着在 .each() 方法之后直接链式调用依赖于主体的其他命令是不安全的。由于 .each() 方法不会更改主体的上下文,所以在 .each() 方法之后直接使用主体可能会导致意外的行为或错误的结果。

  .each() 方法会将相同的主体传递给回调函数,但不会更改主体的上下文。因此,在 .each() 方法之后,最好避免直接链式调用依赖于主体的其他命令,以避免潜在的错误或意外行为。

五、cy.intercept( )

1、语法

cy.intercept(url)
cy.intercept(method, url)
cy.intercept(routeMatcher)
cy.intercept(url, routeHandler)
cy.intercept(method, url, routeHandler)
cy.intercept(routeMatcher, routeHandler)
cy.intercept(url, routeMatcher, routeHandler)

2、用法

cy.intercept("GET", "/ui/tree/children?treeId=vsphere.core*").as("getTreeNodes")

        这行代码使用了 cy.intercept() 方法来拦截一个 GET 请求,该请求的路径为 /ui/tree/children?treeId=vsphere.core*,并为该拦截命名为 "getTreeNodes"

解释该代码的各个部分:

  • cy.intercept(): 这是 Cypress 提供的拦截网络请求的方法。
  • "GET": 拦截的请求的方法为 GET
  • "/ui/tree/children?treeId=vsphere.core*": 拦截的请求路径是 /ui/tree/children?treeId=vsphere.core*,其中 * 表示通配符,可以匹配任意字符。
  • .as("getTreeNodes"): 使用 .as() 方法为拦截命名为 "getTreeNodes",这个名称可以在后续的测试中用来等待或访问该拦截。

        通过这行代码,Cypress 会拦截匹配 /ui/tree/children?treeId=vsphere.core*GET 请求,并命名为 "getTreeNodes"。这使得我们可以在测试中等待该拦截完成,然后对拦截的请求和响应进行验证。

1、拦截 GET 请求并模拟响应

cy.intercept('GET', '/api/data', { statusCode: 200, body: { message: 'Mock response' } }).as('getData');
  • cy.intercept():这是 Cypress 提供的命令,用于拦截和修改网络请求。
  • 'GET':指定要拦截的请求方法,这里是 GET 请求。
  • '/api/data':指定要拦截的请求路径,这里是 /api/data
  • { statusCode: 200, body: { message: 'Mock response' } }:指定拦截请求后返回的响应。这里设置了状态码为 200,响应体为一个包含 message 属性的对象。

.as('getData'):为拦截器指定一个别名 'getData',以便在后续的测试中使用

cy.visit('/my-page');

cy.visit() 命令用于访问指定的页面,这里是 /my-page

cy.wait('@getData').its('response.body').should('deep.equal', { message: 'Mock response' });

cy.wait('@getData'):使用 cy.wait() 命令等待指定别名 'getData' 的请求完成。

.its('response.body'):使用 .its() 来访问响应对象的 response.body 属性。

.should('deep.equal', { message: 'Mock response' }):使用 .should() 断言来验证响应体的内容是否与预期的对象 { message: 'Mock response' } 相等。

        综合起来,这段代码的作用是拦截发送到 /api/data 路径的 GET 请求,并模拟一个成功的响应。然后,测试会访问 /my-page 页面,并等待拦截的请求完成。最后,使用断言来验证响应的响应体是否与预期的对象相等。如果相等,测试将通过。

2、修改请求的响应头和状态码:

cy.intercept('POST', '/api/login', (req) => {
  req.reply((res) => {
    res.headers['Authorization'] = 'Bearer myToken';
    res.statusCode = 200;
    res.send({ success: true });
  });
}).as('loginRequest');
cy.visit('/login');
cy.get('#username').type('myUsername');
cy.get('#password').type('myPassword');
cy.get('#submit').click();
cy.wait('@loginRequest');

        在这个示例中,cy.intercept() 用于拦截发送到 /api/login 路径的 POST 请求,并使用回调函数来修改响应。回调函数接收一个 req 参数,表示拦截的请求对象,你可以在回调函数中修改该请求的属性。在这里,我们修改了响应头的 Authorization 字段和状态码,并发送了一个自定义的响应。然后,在测试中执行登录操作,并等待拦截的请求完成。

3、模拟请求失败:

cy.intercept('GET', '/api/data', { forceNetworkError: true });
cy.visit('/my-page');
cy.contains('Error occurred').should('be.visible');

        这个示例中,cy.intercept() 用于拦截发送到 /api/data 路径的 GET 请求,并模拟一个网络错误。通过设置 { forceNetworkError: true },请求将被模拟为失败,并且页面中会显示相应的错误消息。在测试中使用 cy.visit() 访问页面,并使用 cy.contains() 断言来验证错误消息是否可见。

        通过这些示例,你可以了解到如何使用 cy.intercept() 命令来拦截和模拟网络请求,以满足测试需求。你可以根据具体的测试场景和需求,使用不同的参数和回调函数来定制

3、参数

3.1、method (String)

        用于匹配特定的 HTTP 请求方法(GET、POST、PUT 等)。如果不定义 method,Cypress 默认会匹配所有的请求。

3.2、url (String, Glob, RegExp)

        用于指定要匹配的 URL。可以使用字符串、通配符(Glob)或正则表达式来定义 URL。具体匹配规则可参考 "Matching url" 的说明文档。

3.3、routeMatcher (RouteMatcher)

routeMatcher 是一个用于匹配传入的 HTTP 请求与拦截的路由之间的对象。

  • routeMatcher 对象的所有属性都是可选的,但是如果设置了属性,则必须满足所有设置的属性才能拦截该请求。

  • 如果将字符串传递给任何属性,它将使用 Cypress.minimatch 进行通配符匹配,其中应用了 { matchBase: true } 的 minimatch 选项。

  • 如果没有设置 routeMatcher 参数,cy.intercept() 命令会默认使用 methodurl 参数来匹配请求。

    具体来说,如果没有设置 routeMatcher,则匹配规则如下:

    • 请求方法(method):如果设置了 method 参数,则只匹配与该方法相同的请求方法。例如,如果 method 设置为 'GET',则只会拦截 GET 请求,而不会拦截其他方法的请求。如果未设置 method 参数,则默认匹配所有请求方法。

    • 请求 URL(url):如果设置了 url 参数,则只匹配与该 URL 相同的请求。可以使用字符串、通配符(Glob)或正则表达式来定义 URL。例如,url 设置为 '/api/data',则只会拦截请求该路径的请求。如果未设置 url 参数,则默认匹配所有 URL。

        通过设置 methodurl 参数,cy.intercept() 可以根据请求方法和 URL 进行精确匹配,以拦截特定的请求。但是如果需要更复杂的匹配规则,可以使用 routeMatcher 对象来实现更高级的匹配条件。

        总结起来,cy.intercept() 命令的参数中,method 用于匹配特定的 HTTP 请求方法,url 用于指定要匹配的 URL,可以使用字符串、通配符或正则表达式,而 routeMatcher 是一个可选的对象,用于更精细地匹配传入的 HTTP 请求与拦截的路由之间的条件。

3.4、routeHandler (Function)

        一个回调函数,用于处理匹配的请求。在这个函数中,你可以模拟响应、修改请求、断言或执行其他操作。

4、返回值

cy.intercept() 方法返回一个对象,该对象有一些有用的方法,可以用于进一步配置和操作拦截。常用的方法包括:

  • .as(alias): 为拦截命名,并可通过 cy.wait()cy.route()cy.get() 等命令等待或访问该拦截。为同步
  • .reply(response): 指定模拟的响应。response 可以是字符串、对象或一个回调函数。
  • .intercept()(链式调用): 可以使用 .intercept() 来修改拦截的请求或响应,包括更改请求头、请求体、状态码、响应体等。

5、运行原理

  cy.intercept() 方法的运行原理是在请求发出之前拦截它。

        当你使用 cy.intercept() 方法拦截一个请求时,它会在真实的请求发送之前注册拦截器。这意味着拦截器会捕获该请求,并在请求发送到服务器之前对其进行处理。

        一旦拦截器被注册,它会监听匹配的请求,并在请求被发送之前拦截它。拦截器可以修改请求的各个方面,如请求头、请求体等,或者直接发送自定义的响应。

        这种拦截器的机制允许你在测试中对请求进行控制和模拟,以验证应用程序在不同情况下的行为。你可以模拟不同的响应,触发错误状态,或者对请求进行验证和记录。

        总结起来,cy.intercept() 方法会在请求发出之前拦截它,允许你在发送请求之前对其进行修改或发送自定义的响应。这种机制使得在测试中模拟不同的网络情况和响应变得容易和可控。

六、cy.wait( )

cy.wait() 命令用于在继续执行下一个命令之前等待一定的时间或等待一个命名的资源(alias)解析完成。

1、语法

cy.wait(time)
cy.wait(alias)
cy.wait(aliases)
cy.wait(time, options)
cy.wait(alias, options)
cy.wait(aliases, options)

2、用法

用法一:等待一定的时间

        可以使用 cy.wait() 命令来等待一定的毫秒数,然后再继续执行下一个命令。这对于处理需要一些延迟的情况非常有用,例如等待动画效果完成、等待数据加载等。

cy.wait(2000) // 等待 2000 毫秒(2 秒)
cy.get('.element').should('be.visible')

        在上述示例中,cy.wait(2000) 命令会等待 2000 毫秒(2 秒),然后继续执行后续的命令,即 cy.get('.element').should('be.visible')

用法二:等待命名的资源解析完成

        在使用 cy.intercept().as() 命令拦截请求并命名之后,可以使用 cy.wait() 命令等待特定的资源解析完成,然后再继续执行下一个命令。这对于等待网络请求完成或特定的操作完成非常有用。

cy.intercept('GET', '/api/data').as('getData')
cy.visit('/dashboard')
cy.wait('@getData')
cy.get('.element').should('have.length', 5)

        在上述示例中,cy.wait('@getData') 命令会等待名为 'getData' 的资源(即拦截的请求)解析完成,然后再继续执行后续的命令,即 cy.get('.element').should('have.length', 5)

        通过使用 cy.wait() 命令,可以在测试中添加等待的时间,以便处理需要延迟或异步操作的情况。这确保了在进行后续断言或操作之前,需要的条件已经满足,从而确保了测试的可靠性和稳定性。

用法三:等待多个命名的路由(alias)解析完成

cy.intercept('GET', '/api/users').as('getUsers')
cy.intercept('GET', '/api/posts').as('getPosts')
cy.wait(['@getUsers', '@getPosts']) // 等待多个路由解析完成

3、参数

3.1、time (Number)

要等待的时间,以毫秒为单位。表示等待的持续时间。

3.2、alias (String)

通过使用 .as() 命令定义的命名路由(alias),并用 @ 字符和别名引用。

3.3、aliases (Array)

通过使用 .as() 命令定义的多个命名路由(alias)的数组,可以使用 @ 字符和别名引用。

3.4、options (Object)

4、返回值

4.1、当 cy.wait() 命令给定一个时间参数时:

  • cy.wait() 会返回与它给定的主体相同的主体(subject)。
  • .wait() 之后,不安全在主体上链式调用进一步的依赖于主体的命令。

这意味着,当使用时间参数调用 cy.wait() 命令时,它不会对主体进行任何修改,并且返回的主体与输入的主体相同。因此,可以在 .wait() 之后继续使用相同的主体来进行其他断言或操作。

示例:

cy.get('.element')
  .wait(2000)
  .should('have.class', 'active')

        在上述示例中,.wait(2000) 不会对主体进行修改,并且在等待时间结束后,我们仍然可以使用相同的主体继续进行断言,即 .should('have.class', 'active')

4.2、当 cy.wait() 命令给定一个别名参数时:

  • cy.wait() 会“产生”一个对象,该对象包含请求和响应的 HTTP 属性。

这意味着,当使用别名参数调用 cy.wait() 命令时,它会等待与别名对应的资源完成,并返回一个包含请求和响应属性的对象。这个对象可以在后续的命令中使用,以验证请求和响应的属性、状态等。

示例:

cy.intercept('GET', '/api/data').as('getData')
cy.visit('/dashboard')
cy.wait('@getData').then((interception) => {
  console.log(interception.request)
  console.log(interception.response)
})

        在上述示例中,cy.wait('@getData') 会等待名为 'getData' 的资源完成,并返回一个对象,其中包含请求和响应属性。我们可以使用 .then() 方法访问这个对象,并在控制台中输出请求和响应的内容。

        通过使用正确的参数调用 cy.wait() 命令,我们可以根据需要获取相同的主体或请求和响应的属性,从而进行进一步的断言和验证。

七、cy.request( )

cy.request() 是 Cypress 中用于发送 HTTP 请求的命令。它允许你模拟网络请求并对其进行断言和验证。

1、语法

cy.request(url)
cy.request(url, body)
cy.request(method, url)
cy.request(method, url, body)
cy.request(options)

2、用法

发送一个 GET 请求:

cy.request('GET', 'https://api.example.com/users')
  .then((response) => {
    // 处理响应
    console.log(response.body); // 响应体
    console.log(response.status); // 响应状态码
    console.log(response.headers); // 响应头部信息
  });

发送一个带有请求体的 POST 请求:

cy.request('POST', 'https://api.example.com/users', { name: 'John', age: 25 })
  .then((response) => {
    // 处理响应
    console.log(response.body);
  });

发送一个带有自定义请求头的请求:

cy.request({
  method: 'GET',
  url: 'https://api.example.com/users',
  headers: {
    'Authorization': 'Bearer token123',
    'Content-Type': 'application/json'
  }
})
  .then((response) => {
    // 处理响应
    console.log(response.body);
  });

注意事项:

  • Cypress 的网络请求是绕过真实的网络层,直接在浏览器内部进行模拟和拦截的。因此,cy.request() 发送的请求不会真正离开浏览器,也不会触发实际的网络通信。
  • 在使用 cy.request() 发送请求时,Cypress 不会自动等待请求完成。如果需要等待请求的响应,可以使用 cy.wait() 命令来等待特定的请求完成。
  • cy.request() 可以与其他 Cypress 命令结合使用,例如使用 cy.request() 获取的响应数据进行断言或验证。

3、参数

3.1、url (String)

url (必选):请求的 URL。

3.2、method (String)

method (必选):请求方法,如 "GET"、"POST"、"PUT"、"DELETE" 等。

3.3、body

body (可选):请求的主体数据,通常在发送 POST 或 PUT 请求时使用。可以是字符串或对象。

3.4、options (Object)

4、返回值

cy.request() 命令返回一个包含响应信息的对象字面量的promise对象,其中包括以下属性:

  • status:响应的状态码(HTTP 状态码),表示请求的处理结果,例如 200 表示成功,404 表示未找到资源等。
  • body:响应的主体内容,通常是一个字符串或解析后的 JSON 对象,包含服务器返回的数据。
  • headers:响应的头部信息,包括各种响应头,如 Content-Type、Cache-Control、Authorization 等。
  • duration:请求的持续时间,表示从发送请求到接收响应所花费的时间,以毫秒为单位。

通过访问这些属性,你可以对响应进行进一步的断言、验证和处理。

以下是一个示例,展示如何使用 cy.request() 命令并访问返回的响应属性:

cy.request('GET', 'https://api.example.com/users')
  .then((response) => {
    // 访问响应属性
    console.log(response.status); // 打印响应状态码
    console.log(response.body); // 打印响应主体内容
    console.log(response.headers); // 打印响应头部信息
    console.log(response.duration); // 打印请求持续时间

    // 进行断言和验证
    expect(response.status).to.eq(200); // 断言状态码为 200
    expect(response.body).to.have.length(10); // 断言响应主体长度为 10
  });

        在上述示例中,通过 cy.request() 发送了一个 GET 请求,并使用 .then() 处理返回的响应。通过访问 response 对象的属性,可以获取和处理响应的各个方面。

        需要注意的是,cy.request() 命令返回的是一个 Promise,因此我们使用 .then() 来处理异步操作,并在 Promise 被解析后访问响应属性。

八、cy.log( )

 cy.log()这个命令允许你在测试过程中向命令日志输出自定义的文本消息,用于调试和记录信息。

1、语法

cy.log(message)
cy.log(message, args...)

2、用法

在运行 Cypress 测试时,当遇到 cy.log() 命令时,它将在命令日志中显示你提供的消息。这对于跟踪测试执行、查看特定操作的输出或记录关键信息非常有用。

以下是一个示例,展示了在 Cypress 测试中如何使用 cy.log() 命令:

it('should perform a login', () => {
  cy.log('Starting the login test');
  
  cy.visit('/login');
  
  cy.get('#username').type('testuser');
  cy.get('#password').type('password');
  cy.get('#login-button').click();
  
  cy.log('Login completed');
  
  // 其他测试步骤...
});

        在上述示例中,我们使用 cy.log() 在登录测试中打印了两条自定义消息。这些消息将显示在 Cypress 命令日志中,提供了关于测试执行过程的额外信息。

        需要注意的是,cy.log() 命令只会将消息打印到命令日志中,并不会对测试的执行流程产生任何影响。它主要用于辅助调试和信息记录。

3、参数

3.1、message (String)

传入一个字符串作为参数

4、返回值

cy.log() 命令返回的是 null

        在 Cypress 中,大多数命令(包括 cy.log())都是异步执行的,并且它们并不返回任何有意义的值。相反,它们会在内部操作并影响测试的执行流程。

        因此,虽然 cy.log() 命令会在 Cypress 命令日志中打印一条消息,但它本身不会返回任何有用的结果。它只是用于输出日志信息,以便在测试过程中查看和记录。

以下是一个示例,展示了 cy.log() 返回 null 的行为:

cy.log('This is a log message');
const result = cy.log('Another log message');

console.log(result); // 输出: null

        在上述示例中,我们首先使用 cy.log() 打印了两条日志消息,然后将其赋值给 result 变量。但是,result 的值是 null,因为 cy.log() 不返回任何实际的结果。

        因此,在使用 cy.log() 命令时,不要期望它会返回某个有意义的值,而是将其视为在测试过程中输出消息的一种工具。

九、cy.fixture( )

        用于加载位于文件中的固定数据集。这个命令可以用于模拟数据或提供测试所需的固定数据。

1、语法

cy.fixture(filePath)
cy.fixture(filePath, encoding)
cy.fixture(filePath, options)
cy.fixture(filePath, encoding, options)

2、用法

// 加载名为 'data.json' 的 fixture 文件
cy.fixture('data.json').then((data) => {
  // 使用加载的数据执行一些操作
});

// 加载嵌套在 'users' 文件夹下的 'admin.json' 文件
cy.fixture('users/admin.json').then((adminData) => {
  // 使用加载的 adminData 进行断言或其他操作
});

// 使用特定的编码方式加载 fixture 文件
cy.fixture('data.txt', 'latin1').then((text) => {
  // 使用以 'latin1' 编码方式读取的文本数据执行操作
});

// 使用 null 参数加载 fixture 文件,并获得 Cypress.Buffer 实例
cy.fixture('data.png', null).then((buffer) => {
  // 使用加载的 buffer 执行操作
});

// 使用自定义选项加载 fixture 文件
cy.fixture('data.json', { timeout: 5000 }).then((data) => {
  // 使用加载的数据执行一些操作,超时时间设置为 5 秒
});

3、参数

用于加载位于 fixturesFolder(默认为 cypress/fixtures)中的文件。

3.1、filePath (String)

        文件路径,相对于 fixturesFolder。可以嵌套文件夹并通过定义从 fixturesFolder 开始的路径来引用它们。

3.2、encoding (String)

读取文件时要使用的编码方式。支持以下编码方式:

  • 'ascii'
  • 'base64'
  • 'binary'
  • 'hex'
  • 'latin1'
  • 'utf8' 或 'utf-8'
  • 'ucs2' 或 'ucs-2'
  • 'utf16le' 或 'utf-16le'
  • null(显式使用 null 将返回一个 Cypress.Buffer 实例的 fixture,而不考虑文件扩展名)

3.3、options (Object)

        可选的选项对象,用于更改 cy.fixture() 的默认行为。其中一个可用选项是 timeout,默认为 responseTimeout,表示等待 cy.fixture() 解析完成的超时时间。

4、返回值

cy.fixture() 命令会产生文件的内容作为返回值。文件的格式由其文件扩展名决定。

具体说明如下:

  • cy.fixture() 命令会读取文件的内容,并将其作为一个值返回给后续的操作。
  • 返回的值的格式(比如 JSON、文本、二进制等)会根据文件的扩展名自动确定。
  • 例如,如果加载的文件是一个 JSON 文件(扩展名为 .json),那么返回的值将会被解析为 JSON 对象。
  • 如果文件是文本文件(比如 .txt),返回的值将是文本字符串。
  • 如果文件是二进制文件(如图像文件),返回的值将是二进制数据。

        需要注意的是,cy.fixture() 命令返回的主体对象(subject)不会在磁盘上的内容发生变化时更新。

        这意味着一旦使用 cy.fixture() 命令加载了文件并获得了文件的内容,即使磁盘上的文件内容发生了变化,返回的值也不会随之更新。因此,在使用 cy.fixture() 命令后,对文件的任何后续更改将不会反映在已加载的值中。

        这种行为确保了测试的稳定性和可重复性。如果需要重新加载文件以获取最新的内容,可以在测试中再次使用 cy.fixture() 命令。

第五章、Assertions

第六章、Utilitues

一、Cypress._

        Cypress自动包含了Lodash库,并将其作为Cypress._暴露出来。你可以在Cypress._上调用任何有效的Lodash方法。

        Lodash是一个流行的JavaScript实用工具库,提供了许多用于简化JavaScript开发的常用功能和实用方法。它提供了各种功能,包括集合操作、数组操作、函数式编程、对象操作、字符串操作等等。

1、语法

Cypress._.method()

2、调用forEach方法

        在Cypress中,你可以使用Cypress._来访问Lodash库的方法。例如,如果你想使用Lodash的forEach方法遍历一个数组,你可以这样写:

const numbers = [1, 2, 3, 4, 5];

Cypress._.forEach(numbers, (num) => {
  cy.log(num);
});

        在上面的例子中,我们使用Cypress._.forEach来调用Lodash的forEach方法,对numbers数组进行遍历,并在每个元素上输出日志。

        通过Cypress._,你可以利用Lodash的强大功能来处理和操作数据,以及执行其他常见的编程任务。记住,使用Cypress._时,你可以调用任何有效的Lodash方法。

3、调用times方法

Cypress._.times()方法接受两个参数:niteratee

  • n:一个整数,表示要迭代的次数。
  • iteratee:一个回调函数,用于处理每次迭代。
    • 回调函数参数:index,是从0开始的。在每次迭代中,index参数表示当前迭代的索引,从0开始递增。

在每次迭代中,iteratee函数会接收当前迭代的索引作为参数,并且会被调用n次。

以下是Cypress._.times()的示例用法:

Cypress._.times(5, (index) => {
  cy.log(`Iteration ${index}`);
});

上述代码将迭代5次,并在每次迭代中输出日志,日志中包含当前迭代的索引。

此外,Cypress._.times()方法还可以用于生成重复的数据。你可以在iteratee函数中创建并返回一个值,并将其收集到一个数组中,从而生成重复的数据。

const numbers = Cypress._.times(5, (index) => index + 1);
cy.log(numbers); // [1, 2, 3, 4, 5]

在上面的示例中,我们使用Cypress._.times()生成了一个包含数字1到5的数组。

总结一下,Cypress._.times()是Cypress对Lodash库中times()方法的封装,它允许你在Cypress测试中进行迭代操作,并可以生成重复的数据。

二、jQuery对象的属性

1、length

用来获取并返回匹配的元素数量

三、jQuery对象的方法

1、click()

语法: .click(position, options)  或  .click(x, y, options)

position:发出点击的位置。该center位置是默认位置。有效位置为topLefttoptopRightleftcenterrightbottomLeft,bottom bottomRight

x (数量):从元素左侧发出点击的距离(以像素为单位)

y (数字):从元素顶部到发出点击的距离(以像素为单位)

下面的点击将在元素内部发出(距离左侧 15px,距离顶部 40px):

cy.get('#top-banner').click(15, 40)

options:传入选项对象以更改.click()

 示例:

强制点击元素

cy.get('#collapse-sidebar').click('bottomLeft', { force: true })

点击多个元素

        默认情况下,如果您尝试单击多个元素,Cypress 会出错。通过传递,{ multiple: true }赛普拉斯将迭代地将点击应用到每个元素,并且还将 多次记录到命令日志

cy.get('[id^=btn]').click({ multiple: true })

2、rightclick()

语法:

.rightclick()
.rightclick(options)
.rightclick(position)
.rightclick(position, options)
.rightclick(x, y)
.rightclick(x, y, options)

.rightclick()不会打开浏览器本机的上下文菜单。 .rightclick()应该用于测试您的应用程序对右键单击相关事件的处理,例如contextmenu.

cy.get('.menu').rightclick() // Right click on .menu
cy.focused().rightclick() // Right click on el with focus
cy.contains('Today').rightclick() // Right click on first el containing 'Today'

3、dblclick()

双击 DOM 元素。

语法:

.dblclick()
.dblclick(options)
.dblclick(position)
.dblclick(position, options)
.dblclick(x, y)
.dblclick(x, y, options)

cy.get('button').dblclick() // Double click on button
cy.focused().dblclick() // Double click on el with focus
cy.contains('Welcome').dblclick() // Double click on first el containing 'Welcome'

8、浏览器导航操作

 案例:

describe('浏览器导航', () => {
    it('导航', () => {
        //访问url
        cy.visit('https://www.atstudy.com/'); //使用visit方法返回值必须是一个text/html格式文档
        //点击登录按钮
        cy.get(' button.el-button.pre.el-button--text > span').click();
        //浏览器后退
        cy.go(-1);
        //浏览器前进
        cy.go(1);
        //浏览器刷新
        cy.reload(true);  //优先使用缓存cache,如果不使用缓存,前置刷新,则添加参数true
        //获取url
        console.log(cy.url());
        //获取title
        console.log(cy.title());
    })
})

9、元素定位(默认使用css)

元素定位详解

9.1 简单执行方案

通过cypress打开被测页面

9.2 通过children,parent,sibling,prev,next,within,contains定位元素

element_locators.cy.js
describe('元素定位方法练习',()=>{
    it('使用children,siblings,prev,next定位', () => {
        cy.visit('https://example.cypress.io/commands/querying');
        //使用children()方法定位子元素,适用于子元素不好定位的情况下
        let name_ele=cy.get('.query-form').children('input:first');
        name_ele.type('This is my username!');
        //使用siblings()方法定位同级元素
        let pwd_ele= name_ele.siblings('input');
        pwd_ele.type('123456');
        //使用prev()方法定位紧邻上面同级元素
        name_ele = pwd_ele.prev('input');
        name_ele.clear();    //clear()方法只用于清空input标签的内容
        //使用next()方法定位紧邻下面同级元素
        pwd_ele = name_ele.next();
        pwd_ele.clear();
    });

    it('使用within定位', () => {
        cy.visit('https://example.cypress.io/commands/querying');
        //首先定位到父元素form表单的元素,使用within方法,可以定位到form中任何子元素
        let name_ele=cy.get('.query-form').within(($form)=>{
            cy.get('input:first').type('jiazhuoqun');
            cy.get('input:last').type('123456');
        })
    });

    it('使用contains方法,通过定位元素中的text文本来实现元素定位', () => {
        cy.visit('https://example.cypress.io/commands/actions');
        cy.contains('Submit').click();
    });
})

9.3 定位一闪而过的元素

10、元素操作

元素操作详解

10.1 元素输入

10.2 元素点击

10.3 元素选择

10.3.1 复选框和单选框

 10.3.2 select下拉框

element_opration.cy.js
describe('元素操作相关方法',()=>{
    it('输入操作', () => {
        cy.visit('https://example.cypress.io/commands/actions');
        //使用focus方法进行光标聚焦
        cy.get('#password1').focus().type('123456');
        //使用blur方法进行光标撤离
        cy.get('#fullName1').type('aaa').blur();
        //使用submit方法进行提交表单
        cy.get('#couponCode1').type('123'); 
        cy.get('.action-form').submit();  //必须先定位到form表单元素,才能使用submit方法
    });

    it('点击操作', () => {
        cy.visit('https://example.cypress.io/commands/actions');
        //双击操作
        let ele1= cy.get('.action-div');
        ele1.dblclick();
        //右击操作
        cy.get('.rightclick-action-div').rightclick();
    });

    it('多选,单选使用check方法', () => {
        cy.visit('https://example.cypress.io/commands/actions');
        //多选框 checkbox  
        //选择所有
        // cy.get('.action-checkboxes [type="checkbox"]').not('[disabled]').check();
        cy.get('.action-multiple-checkboxes [type="checkbox"]').not('[disabled]').check();
        //{'force': true} 强制选择
        cy.get('.action-checkboxes [type="checkbox"]').check({'force': true});

        //取消所有
        cy.get('.action-multiple-checkboxes [type="checkbox"]').uncheck({'force': true});
        cy.get('.action-checkboxes [type="checkbox"]').uncheck({'force': true});

        //选择部分
        //选择一个        check中传的参数默认是value属性的值
        cy.get('.action-checkboxes [type="checkbox"]').check('checkbox1');
        //选择多个
        cy.get('.action-multiple-checkboxes [type="checkbox"]').check(['checkbox1','checkbox3']);

        //单选  radio
        cy.get('.action-radios [type="radio"]').check('radio1');
    });

    it('select 下拉框操作', () => {
        cy.visit('https://example.cypress.io/commands/actions');
        //单选下拉框操作
        //通过text文本选择
        cy.get('.action-select').select('bananas');
        //通过value属性值选择
        cy.get('.action-select').select('fr-apples');

        //多选框
        cy.get('.action-select-multiple').select(['oranges','bananas']);
    });
    
})

11、滚动操作

11.1 全局浏览器窗口及元素滚动操作

Browser_window_scrolling.cy.js
describe('浏览器窗口及元素滚动操作',()=>{
    it('浏览器窗口滚动', () => {
        cy.visit('https://example.cypress.io/commands/querying');
        //将目标元素滚到浏览器上方
        cy.get('#inputName').scrollIntoView().type('jiazhuoqun');
        cy.wait(2000);

        //滚动到最顶端
        cy.scrollTo('top');
        cy.wait(2000);

        //滚动到最低端
        cy.scrollTo('bottom');
        cy.wait(2000);

        //通过坐标滚动到指定位置
        cy.scrollTo(0.250);    //0为x坐标,一般不用动,250为y坐标
        cy.wait(2000);

        //通过百分比滚动到指定位置
        cy.scrollTo('0%','50%');
        cy.wait(2000);
    });
})

11.2 子元素窗口滚动操作

The_child_element_window_scrolls.cy.js
describe('子元素窗口滚动操作',()=>{
    it('', () => {
        cy.visit('https://example.cypress.io/commands/actions');
        //定位到子元素,并滑动到可视范围内
        let ele = cy.get('#scrollable-both').scrollIntoView();
        //x轴滑动到最右边
        ele.scrollTo('right');
        cy.wait(2000);
        //x轴滑动到中间
        ele.scrollTo('center');
        cy.wait(2000);
        //y轴滑动到60%位置
        ele.scrollTo('0','60%');
        cy.wait(2000);
    });
})

12、固定等待

cy.wait(2000);      以毫秒为单位,2000为2秒

13、生成allure报告

本地也要安装allure,官网下载,并配置/bin环境变量

使用cypress 和allure集成生成测试报告 - 51Testing软件测试网

命令行能显示allure版本但是vscode中显示allure版本报错解决办法

14、cypress命令行操作

 npx cypress run --spec "cypress\e2e\integration\test_xzm.cy.js" --headed --browser=firefox

 无头模式是指没有浏览器界面(效率更快),有头模式是指由浏览器界面

15、文件上传

安装插件(-dev是指在开发环境中使用,可不加)

cnpm install cypress-file-upload --save-dev

编写一个html文件

cypress/pages/upload_file.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <input type="file" id="mFile">
</body>
</html>

 

upload_file.cy.js
// import 'cypress-file-upload';

describe('',()=>{
    it('', () => {
        cy.visit('http://127.0.0.1:8081/upload_file.html');
        cy.get('#mFile').attachFile('example.json'); //默认查找fixtures目录下文件
    });
})

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值