Skip to content

Element-UI 基础表单测试(含校验)(SimpleForm.vue)

vue
<template>
  <el-form
    :model="ruleForm"
    :rules="rules"
    ref="ruleForm"
    label-width="100px"
    class="demo-ruleForm"
  >
    <el-form-item label="活动名称" prop="name">
      <el-input v-model="ruleForm.name"></el-input>
    </el-form-item>
    <el-form-item label="活动区域" prop="region">
      <el-select v-model="ruleForm.region" placeholder="请选择活动区域">
        <el-option label="区域一" value="shanghai"></el-option>
        <el-option label="区域二" value="beijing"></el-option>
      </el-select>
    </el-form-item>
    <el-form-item label="活动时间" required>
      <el-col :span="11">
        <el-form-item prop="date1">
          <el-date-picker
            type="date"
            placeholder="选择日期"
            v-model="ruleForm.date1"
            style="width: 100%"
          ></el-date-picker>
        </el-form-item>
      </el-col>
      <el-col class="line" :span="2">-</el-col>
      <el-col :span="11">
        <el-form-item prop="date2">
          <el-time-picker
            placeholder="选择时间"
            v-model="ruleForm.date2"
            style="width: 100%"
          ></el-time-picker>
        </el-form-item>
      </el-col>
    </el-form-item>
    <el-form-item label="即时配送" prop="delivery">
      <el-switch v-model="ruleForm.delivery"></el-switch>
    </el-form-item>
    <el-form-item label="活动性质" prop="type">
      <el-checkbox-group v-model="ruleForm.type">
        <el-checkbox label="美食/餐厅线上活动" name="type"></el-checkbox>
        <el-checkbox label="地推活动" name="type"></el-checkbox>
        <el-checkbox label="线下主题活动" name="type"></el-checkbox>
        <el-checkbox label="单纯品牌曝光" name="type"></el-checkbox>
      </el-checkbox-group>
    </el-form-item>
    <el-form-item label="特殊资源" prop="resource">
      <el-radio-group v-model="ruleForm.resource">
        <el-radio label="线上品牌商赞助"></el-radio>
        <el-radio label="线下场地免费"></el-radio>
      </el-radio-group>
    </el-form-item>
    <el-form-item label="活动形式" prop="desc">
      <el-input type="textarea" v-model="ruleForm.desc"></el-input>
    </el-form-item>
    <el-form-item>
      <el-button type="primary" @click="submitForm('ruleForm')"
        >立即创建</el-button
      >
      <el-button @click="resetForm('ruleForm')">重置</el-button>
    </el-form-item>
  </el-form>
</template>
<script>
  export default {
    data() {
      return {
        ruleForm: {
          name: "",
          region: "",
          date1: "",
          date2: "",
          delivery: false,
          type: [],
          resource: "",
          desc: "",
        },
        rules: {
          name: [
            { required: true, message: "请输入活动名称", trigger: "blur" },
            {
              min: 3,
              max: 5,
              message: "长度在 3 到 5 个字符",
              trigger: "blur",
            },
          ],
          region: [
            { required: true, message: "请选择活动区域", trigger: "change" },
          ],
          date1: [
            {
              type: "date",
              required: true,
              message: "请选择日期",
              trigger: "change",
            },
          ],
          date2: [
            {
              type: "date",
              required: true,
              message: "请选择时间",
              trigger: "change",
            },
          ],
          type: [
            {
              type: "array",
              required: true,
              message: "请至少选择一个活动性质",
              trigger: "change",
            },
          ],
          resource: [
            { required: true, message: "请选择活动资源", trigger: "change" },
          ],
          desc: [
            { required: true, message: "请填写活动形式", trigger: "blur" },
          ],
        },
      };
    },
    methods: {
      submitForm(formName) {
        this.$refs[formName].validate((valid) => {
          if (valid) {
            alert("submit!");
          } else {
            console.log("error submit!!");
            return false;
          }
        });
      },
      resetForm(formName) {
        this.$refs[formName].resetFields();
      },
    },
  };
</script>

Element-UI 复杂表单组件测试(含校验)(SimpleForm.spec.js)

js
// src/components/__tests__/SimpleForm.spec.js
import { mount } from "@vue/test-utils";
import SimpleForm from "../JestTest/SimpleForm.vue";
import ElementUI from "element-ui";
import Vue from "vue";
console.warn = jest.fn();
// 全局注册 Element UI(不使用局部 Vue)
Vue.use(ElementUI);

describe("Element-UI 复杂表单组件测试(含校验)", () => {
  let wrapper;

  beforeEach(() => {
    // 每次测试前重新挂载组件
    wrapper = mount(SimpleForm);
  });

  // 测试用例1:表单基础结构渲染验证
  test("表单渲染完整的结构和所有字段", () => {
    // 验证根表单元素
    const form = wrapper.find("form.el-form");
    expect(form.exists()).toBe(true);

    // 验证所有表单项(共7个输入项 + 1个按钮组)
    const formItems = wrapper.findAll(".el-form-item");
    console.log("SimpleForm.spec.js", formItems.length);
    expect(formItems.length).toBe(10);

    // 验证具体字段:活动名称(input)
    const nameLabel = formItems.at(0).find(".el-form-item__label");
    expect(nameLabel.text()).toBe("活动名称");
    expect(formItems.at(0).find(".el-input__inner").exists()).toBe(true);

    // 验证具体字段:活动区域(select)
    const areaLabel = formItems.at(1).find(".el-form-item__label");
    expect(areaLabel.text()).toBe("活动区域");
    expect(formItems.at(1).find(".el-select").exists()).toBe(true);
    expect(formItems.at(1).find(".el-select__caret").exists()).toBe(true);

    // 验证具体字段:活动时间(日期选择器)
    const timeLabel = formItems.at(2).find(".el-form-item__label");
    expect(timeLabel.text()).toBe("活动时间");
    expect(formItems.at(2).find(".el-date-editor").exists()).toBe(true);
    expect(formItems.at(2).find(".el-icon-date").exists()).toBe(true);

    // 验证具体字段:即时配送(switch)
    const deliveryLabel = formItems.at(5).find(".el-form-item__label");
    expect(deliveryLabel.text()).toBe("即时配送");
    expect(formItems.at(5).find(".el-switch").exists()).toBe(true);
    expect(formItems.at(5).find(".el-switch__input").exists()).toBe(true);

    // 验证具体字段:活动性质(checkbox-group)
    const natureLabel = formItems.at(6).find(".el-form-item__label");
    expect(natureLabel.text()).toBe("活动性质");
    expect(formItems.at(6).find(".el-checkbox-group").exists()).toBe(true);
    expect(formItems.at(6).findAll(".el-checkbox").length).toBe(4); // 4个复选框

    // 验证具体字段:特殊资源(radio-group)
    const resourceLabel = formItems.at(7).find(".el-form-item__label");
    expect(resourceLabel.text()).toBe("特殊资源");
    expect(formItems.at(7).find(".el-radio-group").exists()).toBe(true);
    expect(formItems.at(7).findAll(".el-radio").length).toBe(2); // 2个单选框

    // 验证具体字段:活动形式(textarea)
    const formLabel = formItems.at(8).find(".el-form-item__label");
    expect(formLabel.text()).toBe("活动形式");
    expect(formItems.at(8).find(".el-textarea__inner").exists()).toBe(true);

    // 验证按钮组
    const buttons = formItems.at(9).findAll(".el-button");
    expect(buttons.length).toBe(2);
    expect(buttons.at(0).text()).toBe("立即创建"); // 提交按钮
    expect(buttons.at(1).text()).toBe("重置"); // 取消按钮
  });

  // 测试用例2:活动名称必填校验
  test("活动名称未输入时,提交触发必填校验", async () => {
    // 点击提交按钮
    await wrapper.find(".el-button--primary").trigger("click");
    await Vue.nextTick(); // 等待校验提示渲染

    // 验证第一个表单项(活动名称)出现错误提示
    const nameFormItem = wrapper.findAll(".el-form-item").at(0);
    const errorMsg = nameFormItem.find(".el-form-item__error");
    expect(errorMsg.exists()).toBe(true);
    expect(errorMsg.text()).toContain("请输入"); // 匹配"请输入活动名称"
  });

  // 测试用例2.1:活动名称字数限制
  test("活动名称字数限制校验:输入3到5个字符", async () => {
    // 1. 填写活动名称(必填)
    const nameInput = wrapper.find(
      ".el-form-item:nth-child(1) .el-input__inner"
    );
    async function inputText(str, acceptError = false, errMsg = "") {
      await nameInput.setValue(str);
      await nameInput.trigger("blur");
      await Vue.nextTick(); // 等待校验提示渲染
      // 验证第一个表单项(活动名称)出现错误提示
      const nameFormItem = wrapper.findAll(".el-form-item").at(0);
      const errorMsg = nameFormItem.find(".el-form-item__error");
      expect(errorMsg.exists()).toBe(acceptError);
      if (acceptError) {
        expect(errorMsg.text()).toContain(errMsg); // 匹配"请输入活动名称"
      }
    }

    // 2.1.1 少于3个字符
    await inputText("活动", true, "长度在 3 到 5 个字符");
    // 2.1.2 3-5个字符
    await inputText("活动名称", false, "");
    // 2.1.3 超过5个字符
    await inputText("活动名称123", true, "长度在 3 到 5 个字符");
  });

  // 测试用例3:活动名称输入后校验通过
  test("活动名称输入合法值后,校验错误消失", async () => {
    // 找到活动名称输入框并输入内容
    const nameInput = wrapper.find(
      ".el-form-item:nth-child(1) .el-input__inner"
    );
    await nameInput.setValue("测试活动名称");
    await nameInput.trigger("blur"); // 触发失焦校验
    setTimeout(() => {
      // 验证错误提示消失
      const errorMsg = wrapper
        .findAll(".el-form-item")
        .at(0)
        .find(".el-form-item__error");
      // console.log("nameInput::", nameInput.element.value);
      expect(errorMsg.exists()).toBe(false);
    });
  });

  // 测试用例4:活动区域选择功能
  test("活动区域选择后,输入框显示选中值", async () => {
    // 点击选择框触发下拉
    const selectTrigger = wrapper.find(".el-form-item:nth-child(2) .el-select");
    await selectTrigger.trigger("click");
    await Vue.nextTick();

    // 选择第一个选项(区域一)
    const options = wrapper.findAll(".el-select-dropdown__item");
    expect(options.length).toBe(2); // 存在2个选项
    await options.at(0).trigger("click");
    await Vue.nextTick();

    // 验证输入框显示选中值
    const selectInput = wrapper.find(
      ".el-form-item:nth-child(2) .el-input__inner"
    );
    expect(selectInput.element.value).toBe("区域一");
  });

  // 测试用例5:提交按钮触发表单校验并提交
  test("所有必填项填写后,提交触发成功事件", async () => {
    // 1. 填写活动名称(必填)
    const nameInput = wrapper.find(
      ".el-form-item:nth-child(1) .el-input__inner"
    );
    await nameInput.setValue("完整的活动名称");
    await nameInput.trigger("blur");

    // 2. 选择活动区域
    await wrapper
      .find(".el-form-item:nth-child(2) .el-select")
      .trigger("click");
    await Vue.nextTick();
    await wrapper.findAll(".el-select-dropdown__item").at(0).trigger("click");
    await Vue.nextTick();

    // 3. 点击提交按钮
    await wrapper.find(".el-button--primary").trigger("click");
    await Vue.nextTick();

    // 4. 验证无错误提示
    setTimeout(() => {
      const allErrors = wrapper.findAll(".el-form-item__error");
      expect(allErrors.filter((error) => error.exists()).length).toBe(0);

      // 5. 验证提交事件触发
      expect(wrapper.emitted("submit")).toBeTruthy();
    });
  });
});

Released under the MIT License.