自动化 End-End 测试 Nightwatch.js 之踩雷笔记:检查颜色 II

客制化指令

Nightwatch 本身提供的功能虽然已经相当多了,不过或多或少都有些缺失。又或者我们希望能够让整个测试专案更贴合需要被测试的网站时,客制化指令就是一个很好的工具。

建立环境

如果需要撰写客制化指令,就必须先让 Nightwatch 先知道指令们所放的位置:

const nightwatchConfig = {
    custom_commands_path: './commands'
}

透过 nightwatchConfig 定义好位置後,就可以开始写啦~

checkColorSafe()

昨天已经成功利用 getCssProperty() 凑出可以跨浏览器的功能了,不过如果只是把这样的东西写在单一一个测试档案就太可惜了。

透过上一步的设定後,我们可以建立一个 commands 的资料夹,并加入 checkColorSafe.js

commands
 |-- checkColorSafe.js

指令的写法可以分为:

  • Class-style commands
  • Function-style commands

也都可以搭配 Promise, async/await 或是 Nightwatch 的 protocol actions。

如果是利用 Nightwatch 送出 emit 的方式,大概会长这样:

const util = require('util');
const events = require('events');

function checkColorSafe() {
  events.EventEmitter.call(this);
}

// 继承 events class
util.inherits(checkColorSafe, events.EventEmitter);

// 客制化 command 要做的事,传进 3 个参数 selector, cssProperty color
checkColorSafe.prototype.command = function commandFn(
  _selector,
  _cssProperty,
  _color,
) {
  this._stackTrace = commandFn.stackTrace;
  const self = this;

  let color = '';
  // 呼叫原生 api: getCssProperty
  // 把 rgb 转成 rgba ( firefox, safari 专用)
  // 当 command 完成时 emit 'complete' ,让 command 可以继续串接下去
  self.client.api.getCssProperty(_selector, _cssProperty, function(result) {
    color = result.value.includes('rgba(')
      ? result.value
      : result.value.replace('rgb', 'rgba').replace(')', ', 1)');
    if (color === _color) {
      console.log('\x1b[33m%s\x1b[0m', `${result.value} color matched.`);
    } else {
      console.log('\x1b[31m%s\x1b[0m', `${color} not matched to ${_color}`);
      throw new Error(`Wrong color ${color} not matched to ${_color}`);
    }
    self.emit('complete');
  });

  return this;
};

module.exports = checkColorSafe;

不过这样的方式显得相当的长,在较新的的 Nightwatch 中,可以直接利用 Function-style commands 的方式,将指令简单化:

module.exports = {
  command: async function(_selector, _cssProperty, _color) {
    this.getCssProperty(_selector, _cssProperty, function(result) {
      let color = result.value.includes('rgba(')
        ? result.value
        : result.value.replace('rgb', 'rgba').replace(')', ', 1)');
      if (color === _color) {
        console.log('\x1b[33m%s\x1b[0m', `${result.value} color matched.`);
      } else {
        console.log('\x1b[31m%s\x1b[0m', `${color} not matched to ${_color}`);
        throw new Error(`Wrong color ${color} not matched to ${_color}`);
      }
    });
  },
};

虽然变得比较简单,但也会有一些限制:

  1. 指令是以 asynchronous 的方式进行
  2. 如果需要呼叫多项 api,每项都必须是 this 开头,像是:
module.exports = {
  command: async function(_selector, _cssProperty, _color) {
    this.waitForElementPresent('body');
	this.pause(1000)
    this.checkColorSafe('div', 'color', 'rgba(255, 255, 255, 1)')
};

总结

这两天透过建立客制化指令的方式,解决了跨浏览器比对颜色的情境,并了解指令不同的写法与限制。
只不过,这还只是刚开始,接续还有更多不同浏览器的奇妙个性,需要一一克服,而 Firefox/Safari 也不是永远都担任特殊情境的角色,也有 Chrome 的雷点会在後面介绍


<<:  Unity与Photon的新手相遇旅途 | Day3-介面设定、汇入角色、物件操作

>>:  [Day03 - 规划与设计] 建立 Wireframe 让你开发不迷路

[Day23] Array methods 阵列操作方法(1)

前面在讲物件型别的时候只稍微谈到阵列,而其实阵列包含很多种 methods 可以运用,这篇要来练习阵...

风险描述(risk descriptions)

根据ISO 31000,风险是“不确定性对目标的影响(effect of uncertainty o...

Day 11 - 密码攻击方式

出於书本 Chapter 7. Passwords 如果只是因为测试的目的要进行密码破解,记得要考虑...

建立自己Blog系列(三) Hexo next theme 介绍

前言: 为何我会选用Hxeo来当作Blog框架? 有下面几个原因: 因为建立於本地端,所以可以更方便...

Alpine Linux Porting (一点九?)

最近睡太少身体开始亮红灯Orz 来逐步解剖一下Alpine initramfs的init scrip...