Mockjs implements a front-end non-invasive mock solution

background

In the process of project development, the interface format is usually defined first and the front and back end are developed in parallel. If the front end is developed first, because the interface is not yet implemented, you can only write some test data in the code to test the page effect. This resulted in test data intruding into the business code, which had to be deleted when it went live. Nowadays, medium and large applications usually use vuex and Redux state management warehouses. In this case, it is difficult to write test data, because some logic may need to be modified to match the test data, and it is easy to delete or omit the test logic to correct it. At the same time, some request-related bugs are difficult to detect in this way of testing. This leads to heavy front-end pressure in late combined adjustment.

Problems to be solved by the mock scheme

  • Mock data cannot invade business code
  • Mock data and tools cannot be packaged into production code
  • Mock data should be hot-loaded for easy debugging
  • Mock tools cannot affect syncs
  • Mock tools and data should be as minimally intrusive as possible and modularized and pluggable

solution

  • The front-end development environment should be further divided into the following two
    • Front-end tuning environment: No mock tools or data
    • Front-end mock environment: with mock tools and data, mock data is returned to the interface that has registered the mock rules, and requests to the interface that has not configured the mock rules are issued normally
  • throughnodeCommand line arguments, dynamically givenwebpackAdd entry to determine whether to package mock tools and data

Mockjs introduction

Mockjs is a front-end native mock tool that overwrites the XMLHttpRequest object and returns test data if it detects that the requested interface has registered a mock rule before the request is issued, without actually making an AJAX request. For request interfaces that are not registered with mock rules, AJAX requests are made normally. Because native MockJS is not very easy to use, the request interface for the registered mock rule cannot detect its network request at the console because no AJAX request has been issued, causing debugging difficulties. In addition, native MockJS strictly matches interfaces that register mock rules as strings, which results in requests for urls with query strings not being matched and requiring regees to be written to match urls with query strings. So we rewrote the native MockJS to print test data back to the console for easy debugging, and converted the interface string that registers the mock rule into a re that matches the query string. You should use the rewritten mock object when registering your mock rules.

Mockjs combined with projects

  • throughnodeCommand line parameters are dynamically sentwebpackThe code for adding entry is as follows, or a separate configuration file can be configured to achieve the same effect
// config configures the object for Webpack
// Get command line arguments
const processArgvs = process.argv.slice(2)
// Check whether there are mock parameters. If so, add mock tools and data to the original entry
if (processArgvs.includes('mock')) {
  let entry = config.entry
  if (Array.isArray(entry)) {
    entry.push('./src/mock')}else if (typeof entry === 'object') {
    Object.keys(entry).forEach(name= > {
      if (Array.isArray(entry[name])) {
        entry[name].psuh('./src/mock')}else {
        entry[name] = [entry[name], './src/mock']}})}else {
    config.entry = [entry, './src/mock']}}// The above code is added to the webpack configuration file that starts the dev environment
// Start the front-end mock environment with NPM run dev mock
// NPM run dev starts the front-end debugging environment
Copy the code
  • Mock tool and data location in the project folder
SRC | __ mock | __ index. Js / / entry documents, all registered mock rules file to import here | __ utils | | __ the mock. Js / / rewrite mockjs after, Registered mock rules should use the object | | __ formatOptions. Js / / formatting registered mock callback function parameters of the function, in mock. Used in js. | __ user js / / according to the rules of business divisions of mock registration file| __ business. Js / / according to the rules of business divisions of mock registration file
Copy the code
  • The code for mock.js is as follows
import Mock from 'mockjs'
import formatOptions from './formatOptions'

Mock._mock = Mock.mock
Mock.mock = function (url, method, resFunc) {
  if (arguments.length === 1) {
    return this._mock(url)
  }
  if (arguments.length === 2) {
    console.error('Function Mock.mock require three params: url, method, resFunc!!! ')
    return
  }
  if (arguments.length === 3) {
    let methods = ['get'.'post'.'put'.'delete']
    if(! methods.includes(method.toLowerCase())) {console.error('Function Mock.mock\'s second param should be get, post, put, delete!!! ')
      return
    }
    if (typeofresFunc ! = ='function') {
      console.error('Function Mock.mock\'s third param should be a function!!! ')
      return}}// Convert the registered URL into a re that matches the query string
  if (typeof url === 'string') {
    url = url.replace(/\//g.'\ \ /')
    url += '(| \ \? . *) $'
    url = new RegExp(url)
  } else if(! (urlinstanceof RegExp)) {
    console.error('Function Mock.mock\'s first param should be a string or regexp!!! ')
    return
  }
  this._mock(url, method, function (options) {
    // Format the options object
    options = formatOptions(options)
    let res = null
    try {
      res = resFunc(options)
    } catch (err) {
      res = err
    }
    // Prints the returned test data to the console
    console.groupCollapsed(`%c${options.type.toLowerCase()} | ${options.url}`.'color: green; ')
    console.log('%cparams: '.'color: #38f')
    console.log(options.params)
    console.log('%cresponseData: '.'color: #38f')
    console.log(res)
    console.groupEnd()
    console.log('-- -- -- -- -- -- -- -- -- -- -- -- -- -- --')
    return res
  })
}

export default Mock

Copy the code
  • The formatoptions. js code looks like this
// qs is used to serialize form objects
import qs from 'qs'

export default function formatOptions (options) {
  let { url, type, body } = options
  let params = null
  if (type === 'GET' || type === 'DELETE') {
    let index = url.indexOf('? ')
    let paramsString = index > - 1 ? url.slice(index + 1) : ' '
    if(paramsString ! = =' ') {
      params = qs.parse(paramsString)
    }
  } else {
    params = {}
    if (body instanceof FormData) {
      for (let [key, value] of body.entries()) {
        params[decodeURIComponent(key)] = decodeURIComponent(value)
      }
    } else {
      try {
        params = JSON.parse(body)
      } catch (e) {
        params = qs.parse(body)
      }
    }
  }
  if(params ! = =null && Object.keys(params).length === 0) {
    params = null
  }
  return { url, type, params }
}

Copy the code

Rewritten use of MockJS

  • Mock.mock(url, method, resFunc)
    • Url (String) : Interface path to mock, also supports passing in a re (but consider matching with a query String)
    • Method (String): request type:get , post , put , delete, ignore case
    • ResFunc (Function): a Function that produces test data with a callback argument as an options object associated with the request, as follows
{
  url: String.// The requested path
  type: String.// The type of request, GET, POST, PUT, DELETE
  params: Object // Request parameters, if post and PUT are the body content of the request, get and DELETE are the parsed objects of the query string, and null if not
}
Copy the code

Note: The mock.mock () method also supports passing in a template to generate random test data, as with native MockJS, as documented:

The sample

  • The user.js file in the mock folder
// Current file is SRC /mock/user.js
import Mock from './utils/mock'

// Register a POST request
Mock.mock('/api/user/login'.'post', options => {
  let { params } = options The options object contains the requested URL, type, and parameters
  if (params.username && params.password) {
    return {
      data: ' '.code: 200.message: 'Login successful'}}else {
    return {
      data: ' '.code: 300.message: 'Account or password not entered'}}})// Register the GET request
Mock.mock('/api/user/logout'.'get', options => {
  return {
    data: ' '.code: 200.message: 'Logout successful'}})// Register get requests with query parameters
Mock.mock('/api/user/query'.'get', options => {
  return {
    data: options.params,
    code: 200.message: 'ok'}})Copy the code
  • SRC/mock/index. The js folder
import './user'

console.log('% C front-end mock environment started successfully '.'color: #38f; font-weight: bold')

Copy the code
  • After the above configuration is complete, you can start the mock environment and see the following information on the console

  • The request registered with the mock rule is visible on the console after it is issued

For details, see Demo

  • React-mock-demo NPM start mock Enables the mock environment

  • Vue-mock-demo NPM run mock Enables the mock environment