vue自動化單元測試


 1 // 引用vue和需要測試的組件
 2 import Vue from 'vue'
 3 import HelloWorld from '@/components/HelloWorld'
 4 // 創建測試套件,一個測試組件寫一個測試套件
 5 describe('HelloWorld.vue', () => {
 6   // 測試用例,用來測試不同的方法或者顯示的內容
 7   it('should render correct contents', () => {
 8     const Constructor = Vue.extend(HelloWorld)
 9     const vm = new Constructor().$mount()
10     // 判斷頁面中是否有msg所渲染出來的內容
11     // 等價document.querySelector('.hello h1')
12     expect(vm.$el.querySelector('.hello h1').textContent)
13       .to.equal('Welcome to Your Vue.js App')
14   })
15 })

 模仿微博的自動化測試代碼:

  1 import Vue from 'vue'
  2 import SineWeibo from '@/components/SinaWeibo'
  3 import {mount} from 'vue-test-utils'
  4 // 創建測試套件
  5 describe('SinaaWeibo.vue',()=>{
  6 // 創建測試實例------點擊發布按鈕,發布新內容&&個人微博數量+1
  7   it('點擊發布按鈕,發布新內容&&個人微博數量+1',()=>{
  8     // 找到要測試的組件實例,進行掛載
  9     const wrapper=mount(SineWeibo);
 10     // 找到發表微博的輸入內容
 11     const textArea=wrapper.find('.weibo-publish-wrapper textarea')
 12     // 發布按鈕
 13     const buttonOfPublish = wrapper.find('.weibo-publish-wrapper button')
 14     // weiboNews是從mock中獲取的數據,是微博的初始值
 15     const lengthOfWeiboNews = wrapper.vm.weiboNews.length;
 16     // 右邊的關注/粉絲/微博和其數量:2是微博數
 17     const countOfMyWeibo=wrapper.vm.profileData[2].num;
 18     // 模擬新的微博內容
 19     wrapper.setData({newWeiboContent:{
 20         imgUrl: '../../static/image/profile.jpg',
 21         name: 'Lee_tanghui',
 22         resource: '剛剛 來自 網頁版微博',
 23         content: '歡迎來到我的微博',
 24         images: []
 25       }})
 26     // 觸發發布按鈕事件
 27     buttonOfPublish.trigger('click')
 28     // 獲取增加后的微博條數,和右邊的微博數量
 29     const lengthOfWeiboNewsAfterPublish=wrapper.vm.weiboNews.length;
 30     const countOfMyWeiboAfterPublish=wrapper.vm.profileData[2].num
 31     //斷言: 發布后的微博條數是在原來的基礎上+1;
 32     expect(lengthOfWeiboNewsAfterPublish).to.equal(lengthOfWeiboNews + 1);
 33     //斷言: 個人微博數量是在原來的基礎上+1;
 34     expect(countOfMyWeiboAfterPublish).to.equal(countOfMyWeibo + 1);
 35   })
 36   // 測試實例:當文本框無內容時候,不能發表微博到列表,且彈出提示框
 37   it('當文本框中無內容時, 不能發布空微博到微博列表, 且彈出提示框',()=>{
 38     const wrapper=mount(SineWeibo);
 39     // 找到發布框內容
 40     const textArea = wrapper.find('.weibo-publish-wrapper textarea');
 41     // 找到發布按鈕
 42     const buttonOfPublish = wrapper.find('.weibo-publish-wrapper button');
 43     // 獲取下方微博條數
 44     const lengthOfWeiboNews = wrapper.vm.weiboNews.length;
 45     // 獲取右邊微博數
 46     const countOfMyWeibo = wrapper.vm.profileData[2].num;
 47     // 設置發表微博,但是content的內容為空
 48     //設置textArea的綁定數據為空
 49     wrapper.setData({newWeiboContent: {
 50         imgUrl: '../../static/image/profile.jpg',
 51         name: 'Lee_tanghui',
 52         resource: '剛剛 來自 網頁版微博',
 53         content: '',
 54         images: []
 55       }});
 56     // 觸發發布按鈕
 57     buttonOfPublish.trigger('click');
 58     // 獲取發表后的下方微博條數
 59     const lengthOfWeiboNewsAfterPublish = wrapper.vm.weiboNews.length;
 60     // 獲取發表后的下右邊微博數
 61     const countOfMyWeiboAfterPublish = wrapper.vm.profileData[2].num;
 62     // 斷言:發表前后的微博條數是相等的
 63     //斷言: 沒有發布新內容
 64     expect(lengthOfWeiboNewsAfterPublish).to.equal(lengthOfWeiboNews);
 65     //斷言: 個人微博數量不變
 66     expect(countOfMyWeiboAfterPublish).to.equal(countOfMyWeibo);
 67   });
 68 
 69 
 70   // 測試實例:當點擊"關注", 個人頭像下關注的數量會增加1個, 且按鈕內字體變成"取消關注
 71    it('當點擊"關注", 個人頭像下關注的數量會增加1個, 且按鈕內字體變成"取消關注',()=>{
 72       // 獲取wrapper
 73      const wrapper = mount(SineWeibo);
 74      // 獲取“關注”button
 75      const buttonOfAddAttendion = wrapper.find('.add');
 76      // 獲取右邊的關注數量
 77      const countOfMyAttention = wrapper.vm.profileData[0].num;
 78      // 觸發“關注”button
 79      buttonOfAddAttendion.trigger('click');
 80      // 獲取右邊的關注數量
 81      const countOfMyAttentionAfterClick = wrapper.vm.profileData[0].num;
 82      // 斷言1:右邊的關注數量等於原來的+1;
 83      expect(countOfMyAttentionAfterClick).to.equal(countOfMyAttention + 1);
 84      // 斷言2:button的text變為“取消關注”
 85      expect(buttonOfAddAttendion.text()).to.equal('取消關注');
 86 
 87    })
 88 
 89 
 90   // 測試實例:當點擊"取消關注", 個人頭像下關注的數量會減少1個, 且按鈕內字體變成"關注
 91    it('當點擊"取消關注", 個人頭像下關注的數量會減少1個, 且按鈕內字體變成"關注',()=>{
 92      const wrapper=mount(SineWeibo)
 93      // 找到“取消關注”按鈕
 94      const buttonOfUnAttendion = wrapper.find('.cancel');
 95      // 獲取右邊關注人數
 96      const countOfMyAttention = wrapper.vm.profileData[0].num;
 97      // 觸發“取消關注”按鈕的點擊事件
 98      buttonOfUnAttendion.trigger('click');
 99      // 獲取右邊關注人數
100      const countOfMyAttentionAfterClick = wrapper.vm.profileData[0].num;
101      //  斷言1:右邊的人數為原來的人數-1
102      expect(countOfMyAttentionAfterClick).to.equal(countOfMyAttention - 1);
103      //  斷言2:cancel的text變成"關注"
104      expect(buttonOfUnAttendion.text()).to.equal('關注');
105    })
106 
107   it('當點擊"收藏"時, 我的收藏會增加1個數量, 且按鈕內文字變成"已收藏"', () => {
108     const wrapper = mount(SineWeibo);
109     const buttonOfCollect = wrapper.find('.uncollectedWeibo');
110     const countOfMyCollect = Number(wrapper.find('.collect-num span').text());
111 
112     //觸發點擊事件
113     buttonOfCollect.trigger('click');
114     const countOfMyCollectAfterClick = Number(wrapper.find('.collect-num span').text());
115 
116     //斷言: 我的收藏數量會加1
117     expect(countOfMyCollectAfterClick).to.equal(countOfMyCollect + 1);
118     //斷言: 按鈕內文字變成已收藏
119     expect(buttonOfCollect.text()).to.equal('已收藏');
120   })
121 
122   it('當點擊"已收藏"時, 我的收藏會減少1個數量, 且按鈕內文字變成"收藏"', () => {
123     const wrapper = mount(SineWeibo);
124     const buttonOfUnCollect = wrapper.find('.collectedWeibo');
125     const countOfMyCollect = Number(wrapper.find('.collect-num span').text());
126 
127     //觸發點擊事件
128     buttonOfUnCollect.trigger('click');
129     const countOfMyCollectAfterClick = Number(wrapper.find('.collect-num span').text());
130 
131     //斷言: 我的收藏數量會減1
132     expect(countOfMyCollectAfterClick).to.equal(countOfMyCollect - 1 );
133     //斷言: 按鈕內文字變成已收藏
134     expect(buttonOfUnCollect.text()).to.equal('收藏');
135   });
136 
137   it('當點擊"已收藏"時, 我的收藏會減少1個數量, 且按鈕內文字變成"收藏"', () => {
138     const wrapper = mount(SineWeibo);
139     const buttonOfUnCollect = wrapper.find('.collectedWeibo');
140     const countOfMyCollect = Number(wrapper.find('.collect-num span').text());
141 
142     //觸發點擊事件
143     buttonOfUnCollect.trigger('click');
144     const countOfMyCollectAfterClick = Number(wrapper.find('.collect-num span').text());
145 
146     //斷言: 我的收藏數量會減1
147     expect(countOfMyCollectAfterClick).to.equal(countOfMyCollect - 1 );
148     //斷言: 按鈕內文字變成已收藏
149     expect(buttonOfUnCollect.text()).to.equal('收藏');
150   });
151 
152   it('當點擊"贊", 我的贊會增加1個數量, 且按鈕內文字變成"取消贊"', () => {
153     const wrapper = mount(SineWeibo);
154     const buttonOfLike = wrapper.find('.dislikedWeibo');
155     const countOfMyLike = Number(wrapper.find('.like-num span').text());
156 
157     //觸發點擊事件
158     buttonOfLike.trigger('click');
159     const countOfMyLikeAfterClick = Number(wrapper.find('.like-num span').text());
160 
161     //斷言: 我的贊會增加1個數量
162     expect(countOfMyLikeAfterClick).to.equal(countOfMyLike + 1);
163     //斷言: 按鈕內文字變成取消贊
164     expect(buttonOfLike.text()).to.equal('取消贊');
165   });
166 
167   it('當點擊"取消贊", 我的贊會減少1個數量, 且按鈕內文字變成"贊"', () => {
168     const wrapper = mount(SineWeibo);
169     const buttonOfDislike = wrapper.find('.likedWeibo');
170     const countOfMyLike = Number(wrapper.find('.like-num span').text());
171 
172     //觸發點擊事件
173     buttonOfDislike.trigger('click');
174     const countOfMyLikeAfterClick = Number(wrapper.find('.like-num span').text());
175 
176     //斷言: 我的贊會增加1個數量
177     expect(countOfMyLikeAfterClick).to.equal(countOfMyLike - 1);
178     //斷言: 按鈕內文字變成取消贊
179     expect(buttonOfDislike.text()).to.equal('贊');
180   });
181 })

模仿微博的vue 代碼:

<template>
  <div class="weibo-page">
    <nav>
      <span class="weibo-logo"></span>
      <div class="search-wrapper">
        <input type="text" placeholder="大家正在搜: 李棠輝的文章好贊!">
        <img v-if="!iconActive" @mouseover="mouseOverToIcon" src="../../static/image/search.png" alt="搜索icon">
        <img v-if="iconActive" @mouseout="mouseOutToIcon" src="../../static/image/search-active.png" alt="搜索icon">
      </div>
    </nav>
    <div class="main-container">
      <aside class="aside-nav">
        <ul>
          <li :class="{ active: isActives[indexOfContent] }" v-for="(content, indexOfContent) in asideTab" :key="indexOfContent" @click="tabChange(indexOfContent)">
            <span>{{content}}</span>
            <span class="count">
              <span v-if="indexOfContent === 1" class="collect-num">
              (
                <span>{{collectNum}}</span>
              )
              </span>
              <span v-if="indexOfContent === 2" class="like-num">
              (
                <span>{{likeNum}}</span>
              )
              </span>
            </span>
          </li>
        </ul>
      </aside>
      <main class="weibo-content">
        <div class="weibo-publish-wrapper">
          <img src="../../static/image/tell-people.png"></img>
          <textarea v-model="newWeiboContent.content"></textarea>
          <button @click="publishNewWeiboContent">發布</button>
        </div>
        <div
          class="weibo-news"
          v-for="(news, indexOfNews) in weiboNews"
          :key="indexOfNews">
          <div class="content-wrapper">
            <div class="news-title">
            <div class="news-title__left">
              <img :src="news.imgUrl">
              <div class="title-text">
                <div class="title-name">{{news.name}}</div>
                <div class="title-time">{{news.resource}}</div>
              </div>
            </div>
            <button
              class="news-title__right add"
              v-if="news.attention === false"
              @click="attention(indexOfNews)">
              <i class="fa fa-plus"></i>
              關注
            </button>
             <button
              class="news-title__right cancel"
              v-if="news.attention === true"
              @click="unAttention(indexOfNews)">
              <i class="fa fa-close"></i>
              取消關注
            </button>
          </div>
          <div class="news-content">{{news.content}}</div>
          <div class="news-image" v-if="news.images.length">
            <img
            v-for="(img, indexOfImg) in news.images"
            :key="indexOfImg"
            :src="img">
          </div>
          </div>
          <ul class="news-panel">
            <li
              :class="{uncollectedWeibo: !news.collect, collectedWeibo: news.collect}"
              @click="handleCollect(indexOfNews)">
              <i class="fa fa-star-o" :class="{collected: news.collect }"></i>
              {{news.collect ? "已收藏" : '收藏'}}
            </li>
            <li>
              <i class="fa fa-external-link"></i>
              轉發
            </li>
            <li>
              <i class="fa fa-commenting-o"></i>
              評論
            </li>
            <li
              :class="{dislikedWeibo: !news.like, likedWeibo: news.like}"
              @click="handleLike(indexOfNews)">
              <i class="fa fa-thumbs-o-up" :class="{liked: news.like}"></i>
              {{news.like ? '取消贊' : '贊'}}
            </li>
          </ul>
        </div>

      </main>
      <aside class="aside-right">
        <div class="profile-wrapper">
          <div class="profile-top">
            <img src="../../static/image/profile.jpg">
          </div>
          <div class="profile-bottom">
            <div class="profile-name">Lee_tanghui</div>
            <ul class="profile-info">
              <li
                v-for="(profile, indexOfProfile) in profileData"
                :key="indexOfProfile">
                <div class="number">{{profile.num}}</div>
                <div class="text">{{profile.text}}</div>
              </li>
            </ul>
          </div>
        </div>
      </aside>
    </div>
    <footer>
       Wish you like my blog! --- LITANGHUI
    </footer>
  </div>
</template>

<script>
  //引入假數據
  import * as mockData from '../mock-data.js'

  export default {
    created() {
      //模擬獲取數據
      this.profileData = mockData.profileData;
      this.weiboNews = mockData.weiboNews;
      this.collectNum = mockData.collectNum;
      this.likeNum = mockData.likeNum;

    },
    data() {
      return {
        iconActive: false,
        asideTab: ["首頁", "我的收藏", "我的贊"],
        isActives: [true, false, false],
        profileData: [],
        weiboNews: [],
        collectNum: 0,
        likeNum: 0,
        newWeiboContent:   {
          imgUrl: '../../static/image/profile.jpg',
          name: 'Lee_tanghui',
          resource: '剛剛 來自 網頁版微博',
          attention:false,
          content: '',
          images: []
        },
      }
    },
    methods: {
      mouseOverToIcon() {
        this.iconActive = true;
      },
      mouseOutToIcon() {
        this.iconActive = false;
      },
      tabChange(indexOfContent) {
        this.isActives.forEach((item, index) => {
          index === indexOfContent ?
            this.$set(this.isActives, index, true) :
            this.$set(this.isActives, index, false);
        })
      },
      publishNewWeiboContent() {
        if(!this.newWeiboContent.content) {
          alert('請輸入內容!')
          return;
        }
        const newWeibo = JSON.parse(JSON.stringify(this.newWeiboContent));
        this.weiboNews.unshift(newWeibo);
        this.newWeiboContent.content = '';
        this.profileData[2].num++;
      },
      attention(index) {
        this.weiboNews[index].attention = true;
        this.profileData[0].num++;
      },
      unAttention(index) {
        this.weiboNews[index].attention = false;
        this.profileData[0].num--;
      },
      handleCollect(index) {
        this.weiboNews[index].collect = !this.weiboNews[index].collect;
        this.weiboNews[index].collect ?
        this.collectNum++ :
        this.collectNum--;
      },
      handleLike(index) {
        this.weiboNews[index].like = !this.weiboNews[index].like;
        this.weiboNews[index].like ?
        this.likeNum++ :
        this.likeNum--;
      }
    }
  }
</script>

<style lang="less">
  * {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
  }

  .weibo-page {
    display: flex;
    flex-direction: column;
  }

  nav {
    display: flex;
    height: 60px;
    line-height: 60px;
    background-color: #f0f0f0;
    align-items: center;
    .weibo-logo {
      margin-left: 13%;
      width: 100px;
      height: 28px;
      background: url("../../static/image/WB_logo.png") no-repeat;
      cursor: pointer;
    }
    .search-wrapper {
      display: flex;
      position: relative;
      width: 25%;
      input {
        width: 100%;
        height: 24px;
        padding-left: 10px;
      }
      img {
        position: absolute;
        right: 10px;
        top: 4px;
        width: 20px;
        height: 20px;
        cursor: pointer;
      }
    }

  }

  .main-container {
    display: flex;
    justify-content: center;
    background-color: #000;
    padding-top: 16px;
    color: #fff;
    .aside-nav {
      width: 11.31%;
      ul {
        list-style: none;
        li {
          height: 34px;
          line-height: 34px;
          padding-left: 10px;
          cursor: pointer;
          font-weight: bold;
          background-color: rgb(19, 19, 19);
        }
        li:hover {
          background-color: rgb(66, 66, 66);
        }
        .active {
          background-color: rgb(66, 66, 66);
        }
      }
    }
    .weibo-content {
      width: 45.41%;
      color: #000;
      .weibo-publish-wrapper {
        background: #fff;
        position: relative;
        padding: 10px 10px 54px 10px;
        textarea {
          display: block;
          width: 100%;
          height: 95px;
          padding: 10px;
        }
        button {
          position: absolute;
          right: 10px;
          bottom: 10px;
          width: 82px;
          height: 30px;
          background: #ff8140;
          border: 1px solid #f77c3d;
          color: #fff;
          box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.25);
          cursor: pointer;
        }
      }
      .weibo-news {
        background: #fff;
        margin: 10px 0;
        .content-wrapper {
          padding: 20px 20px 4px 20px;
        }
        .news-title {
          display: flex;
          justify-content: space-between;
          .news-title__left {
            display: flex;
            img {
              width: 50px;
              height: 50px;
              vertical-align: text-top;
            }
            .title-text {
              display: flex;
              flex-direction: column;
              justify-content: space-around;
              margin-left: 10px;
            }
            .title-name {
              color: #333;
              font-size: 14px;
              font-weight: 700;
            }
            .title-time {
              color: #808080;
              margin-bottom: 2px;
              font-size: 12px;
            }
          }
          .news-title__right {
            align-self: center;
            width: 58px;
            height: 22px;
            line-height: 22px;
            background: #fff;
            border: 1px solid #d9d9d9;
            cursor: pointer;
            img {
              position: relative;
              left: 1px;
              top: 2px;
            }
            i {
              color: #ff8140;
            }
          }
          .cancel {
            width: 86px;
          }
        }
        .news-content {
          padding: 10px 0 10px 60px;
          font-size: 14px;
        }
        .news-image {
          padding: 10px 0 0 60px;
          img {
            width: 110px;
            height: 110px;
            margin-right: 10px;
          }
        }
        .news-panel {
          display: flex;
          list-style: none;
          border-top: 1px solid #f2f2f5;
          li {
            width: 25%;
            height: 22px;
            line-height: 22px;
            margin: 7px 0;
            text-align: center;
            border-left: 1px solid #f2f2f5;
            color: #808080;
            cursor: pointer;
            .collected {
              color: #ff8140;
            }
            .like {
              color: #ff8140;
            }
          }
        }
      }
    }
    .aside-right {
      width: 17.41%;
      margin-left: 10px;
      .profile-top {
        position: relative;
        height: 75px;
        background: url('../../static/image/profile-bg.jpg');
        img {
          position: absolute;
          bottom: -30px;;
          left: 50%;
          margin-left: -30px;
          width: 60px;
          height: 60px;
          border-radius: 50%;
        }
      }
      .profile-bottom {
        height: 118px;
        padding-top: 30px;
        background: #fff;
        color: #000;
        .profile-name {
          text-align: center;
          font-weight: 700;
        }
        .profile-info {
          display: flex;
          list-style: none;
          padding-top: 10px;
          li {
            width: 33.333%;
            border-left: 1px solid #f2f2f5;
            cursor: pointer;
            div {
              text-align: center;
            }
            .number{
              font-weight: 700;
            }
          }
        }
      }
    }
  }

  footer {
    height: 100px;
    line-height: 100px;
    text-align: center;
    font-size: 12px;
    font-weight:700;
  }
</style>

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM