Uninote
Uninote
用户根目录

user/* 编写规范

user configs 代码生成

node generate 命令会批量处理所有的接口文件,根据每个接口的定义生成对应的配置,如

export async function getUserInfo() {
  return await post({
    url: '/api/user/info',
    data: {}
  });
}

则生成内容为:

  'getUserInfo': {
    '__proto__': base.getUserInfo,
    'api': apis.getUserInfo,
    'desc': "获取用户信息",
    'url': '/api/user/info',
    'defaults': {
    },
    'generated': {},
    'user': {},
    'geneArgs': [
      {
        'scene': 'default',
        'desc': '',
        'type': NORMAL,
        'func': async (ctx) => {
          ctx.generated = {};
        }
      },
    ],
  },

部分字段意义如下:

  • defaults: 配置默认参数
  • generated: 接收生成参数的对象,在 geneArgs 中编写生成参数的逻辑
  • geneArgs: 参数生成函数数组,数组中每个元素是一个如下结构的对象,具体稍后解释
  • 其他参数不要改动

另外支持部分额外的属性配置:

after/before -- after/before request callback

可以配置在 api (top level),或者配置在 gene,其中 info 参数为请求结果:

  'getOne': {
    '__proto__': base.getOne,
    'api': apis.getOne,
    'desc': "获取优惠券信息",
    'url': '/scmsapi/coupon/getOne',
    'defaults': {
      id: '',
    },
    'generated': {},
    'user': {},
    'after': (ctx, info) => {   // <------------------------ api level
      // console.debug('top level after', ctx, info);
    },
    'geneArgs': [
      {
        'scene': 'default',
        'desc': '',
        'type': NORMAL,
        'func': async (ctx) => {
          ctx.generated = {
            id: await getOneID(),
          };
        },
        'validate': (ctx, info) => {
        },
        'after': (ctx, info) => {
          ctx.after(ctx, info); // <------------------------ gene level
          // console.debug('gene level after', ctx, info);
        },

__init 模块异步初始化

http://v.uninote.com.cn/video_play.html?video_url=https://admin.bb.uninote.com.cn/oss?path=video/upload/202109/20210923_143735.mp4

http://v.uninote.com.cn/video_play.html?video_url=https://admin.bb.uninote.com.cn/oss?path=video/upload/202109/20210923_144007.mp4

http://v.uninote.com.cn/video_play.html?video_url=https://admin.bb.uninote.com.cn/oss?path=video/upload/202109/20210923_145759.mp4

有的时候模块加载完成后还需要进行异步初始化操作,我们可以将这些操作放在一个名为 __init 的异步函数中,这样 powder 会等待初始化完成才进行后续操作(比如批量验证)

// powder/user/scms/coupon.js

import * as scms from '../../../tests/scms';

// 公共缓存数据
let scmsCommon;

// 异步初始化接口
export const __init = async(force = false) => {
  scmsCommon = await scms.scmsCommon(force);
};

在切换选择的模块后,也会自动调用切换模块的__init:

  • 注意,刷新时会自动加载上次选择的模块,进而调用该模块的__init

上面的情况都是自动调用,但有一种情况,需要手动调用:有时在 A 中引用了 B,如果 B 需要异步初始化,需要手动调用 B 的 __init,注意 return 了 __init 返回的 promise:

// powder/user/client/shop/coupon.js

import * as scms_coupon from '../../../user/scms/coupon';

// 异步初始化接口
export const __init = async() => {
  return scms_coupon.__init();
};

geneArgs 参数生成函数数组配置

默认会生成一个函数,可以配置 0 - n 个,配置样例如下,用法参见注释:

    'geneArgs': [
      {
        'scene': 'default', // 生成函数名
        'desc': '默认,生成一个普通订单', // 生成函数描述
        'type': NORMAL, // 见 type 节
        'func': async (ctx) => {
          /*
           * 注意这是一个 async 函数,可以通过任何必要方式生成参数
           */
          ctx.generated = {
            order_no: (await createOrder()).order_no,
          };
        }
      },
    ]

此函数即为参数生成(回调)函数。

函数默认接收一个 ctx 参数。ctx.generated为接收生成参数的对象。ctx为当前接口配置对象。

可以为函数增加额外的参数。

  'confirm': {
    'geneArgs': [
      {
        'scene': 'default',
        'desc': '',
        'type': NORMAL,
        'func': async (ctx, arg1, arg2) => {
          ctx.generated = {};
        }
      },
    ],
  }

  // 则传参调用为(注意第一个参数传递场景值):
  confirm.make('default', arg1, arg2);

type

可能值:NORMAL, INNER, GENE_ONLY, NO_BATCH

  • INNER 与 GENE_ONLY 配合使用,类似于 NO_BATCH,并且不会在 UI 显示
    • 注意,INNER 没有 private 的意思,可以跨越接口调用
  • GENE_ONLY 一般与 INNER 配合使用来批量处理数据,因此生成的参数再用来请求没有意义,UI 测试时请求按钮背景会变为黄色以提醒
    • 案例:批量确认收货、批量发货
      • create-multi-sku-comfirm-all
      • create-multi-sku-dispatch-all
  • NORMAL 默认值
  • NO_BATCH 批量时不执行(批量指以下三个按钮触发的批量操作)

noCode

可选。如果设为 true,则不校验返回数据的 code

      {
        'scene': 'with-no',
        'desc': '用于发货的时候指定物流单号调用',
        'type': INNER,
        'noCode': true,
        'func': async (ctx,express_number) => {
          ctx.generated = {
            express_number
          };
        }

完整验证

配置示例:

    'geneArgs': [
      {
        'scene': 'default',
        'func': async (ctx) => {
          ctx.generated = {
              // 1
          };
        },
        'validate': (ctx, info) => {
          ctx.__info = info; // 2
        },
        'testSuites': [
          {
            'name': 'suc',
            'validate': (ctx, info) => {
                // 5
            },
            'tests': [
              (ctx) => { // 3
                ctx.generated.type = '1';
              },
              (ctx) => {
                ctx.generated.code = 1;
                return (ctx, info) => {
                    // 4
                }
              },
            ]
          },
          {
            'name': 'fail',
            'validate': (ctx, info) => {
              utils.assert(info.data.code === 10000, '参数验证失败');
            },
            'tests': [
              (ctx) => {
                ctx.generated.type = '0';
              },
            ]
          }
        ],
      },

示例解释

对每一个接口,会遍历其所有的参数生成函数(后面简称gene),调用一次gene生成参数,再调用若干次接口本身发送请求,对请求结果进行如下验证(为了描述简洁,下面的 1 2 3 ... 与注释对应):

  • 调用gene,生成参数
    • 这里写 gene 的实现代码 1
      • 注:如果存在接口依赖,需要调用其他接口获取数据,注意用 await 等待接口返回
      • 注:gene生成的是公共参数,会被所有的后续tests共享
  • gene返回后,所有参数就绪,调用接口本身发送请求,得到返回结果info
    • 检验状态码(没有配置 noCode 的情况下)
    • info与 api 配置的返回值进行比对(如果有)
    • info进行验证 2
  • 获取testSuites,对每一个test suite进行如下操作:
    • 获取当前 suite 的tests(test cases), 每一个test即为一个测试单元(对应一个函数 3),会做以下事情:
      • 执行前置操作(setup),会在gene生成的公共参数基础之上修改 3
      • 调用接口本身发送请求,得到返回结果info
      • info进行验证(三级验证,但仅调用优先级最高的一个)
        • if return false, 不做任何验证
        • if setup返回一个函数,则此函数将作为验证函数被回调;如果返回值是 false, 则跳过 request & validate 4
        • else if 当前test suite定义了validate,则此validate将作为验证函数被回调 5
        • else if 当前gene定义了validate,则此validate将作为验证函数被回调 2

更多示例

每一个 test 也可以是异步函数:

    'tests': [
      async (ctx) => {
        ctx.generated.type = '0';
      },

tests 也可以配置为一个数组,数组的元素为参数必传字段名,这样会为每个字段发起一次请求,此请求不会包含此字段,用以验证后端是正确否处理字段缺失的情况。

'testSuites': [
  {
    'name': 'fail',
    'validate': assertParamEmpty, // 通用的字段缺失报错验证
    'tests': ['aid', 'path', 'version'],
  },

powder-tools

powder-规范

点赞(0) 阅读(1) 举报
目录
标题