This is the 21st day of my participation in the November Gwen Challenge. Check out the event details: The last Gwen Challenge 2021

Hello ~ I’m Milo! I am building an open source interface testing platform from 0 to 1, and I am also writing a complete tutorial corresponding to it. I hope you can support it. Welcome to pay attention to my public number test development pit goods, get the latest article tutorial!

review

We supported the Redis preconditions, but there is one particularly unfriendly aspect:

If the preconditions are close, I can’t even copy them.

It would be very unfriendly to choose one to copy quickly, just like the pre-case.

So we’re going to do that in this video.

rendering

As usual, here are the renderings:

Train of thought

It’s actually relatively simple for the back end to support this operation.

Fortunately, our backend Constructor has a type field that distinguishes the types of preconditions. So we just need to arrange a query interface:

Find out the details of the preconditions according to the type, and then select, the front end with a form to bring in, you can copy the entire preconditions.

Back end first

Write the query interface, show which case it belongs to, and give details of the preconditions.

The front end has the TreeSelect component identified, so the back end uses a two-tier data format:

[{"title": "Use cases"."key": "caseid"."children": [{"title": "Data constructor A"."key":
      "constructor_id"}}]]Copy the code

Let’s build it

  • Write the ideas

    I do not plan to use join(I have carried out this idea from the very beginning. I prefer to use two queries and join the data by myself. Actually, JOIN is not well used)

    We first check the preconditions of the corresponding type, and then we can get all the case_id, and then use case_id to check the case information, isn’t it beautiful?

    The difficulty is how to form the tree, but actually the tree has only two layers. What we need to do is to assemble children first and then parent.

    This is where defaultdict comes in.

    1. Check the preconditions that meet the conditions and save them to defaultdict based on case_id as key and value as preconditions
    2. Find the case name of case_id from defaultdict keys, iterate over it, piece together the parent, and place the value from Defaultdict into the children field.

    Let’s look at the code:

    @staticmethod
    async def get_case_and_constructor(constructor_type: int) :
        # finally return the result tree
        ans = list(a)async with async_session() as session:
            # where case_id => preconditions are mapped
            constructors = defaultdict(list)
            # select all preconditions according to the type of preconditions passed in
            query = await session.execute(
                select(Constructor).where(
                    Constructor.type == constructor_type,
                    Constructor.public == True,
                    Constructor.deleted_at == None))
            # and put these preconditions in constructors
            for q in query.scalars().all():
                constructors[q.case_id].append({
                    "title": q.name,
                    "key": f"{q.id}"."isLeaf": True.Because trees usually only have name and ID, we need other data
                    "constructor_json": q.constructor_json,
                })

            Select * from case where preconditions exist
            query = await session.execute(
                select(TestCase).where(TestCase.id.in_(constructors.keys()), TestCase.deleted_at == None))
            # Construct the tree, know that children have already built it, right inside the constructors
            for q in query.scalars().all() :Add the use-case ID to the cs_list instead of the native JOIN
                ans.append({
                    "title": q.name,
                    "key": f"case_{q.id}"."disabled": True."children": constructors[q.id]})return ans

Copy the code

Notes are written in great detail and every step is explained clearly.

Next comes the interface section, which needs no further explanation:

Get all data constructors
@router.get("/constructor/list")
async def list_case_and_constructor(constructor_type: int) :
    try:
        ans = await ConstructorDao.get_case_and_constructor(constructor_type)
        return PityResponse.success(ans)
    except Exception as e:
        return PityResponse.failed(str(e))
Copy the code

The front-end adaptation

Front-end adaptation is as simple as adding a component and updating the form’s value when the component selects the value.

oh shit~~

Until now I realize THAT I have written similar code, sad = =

Sure enough, you’re going to fall in the same place, but I don’t think there’s any classification of the preconditions that I wrote before, so I’m going to have to modify it, or I’m going to write it this time as a V2 interface.

I have to say, the front end is a little bigger than expected. A closer look at the interface shows that the logic is:

  1. Find the corresponding precondition ID
  2. Query the preconditions and replace them

However, the previous interface is only for case types, so it is very weak.

We currently make it a new version of the ship for all of our types:

import {Col, Row, TreeSelect} from "antd";
import {connect} from 'umi';
import {useEffect} from "react";

const CopyTreeSelect = ({construct, dispatch}) = > {

  const {constructorData.searchConstructor.constructorType} = construct;


  const save = (data) = > {
    dispatch({
      type: 'construct/save'.payload: data,
    })
  }

  const getConstructorData = () = > {
    dispatch({
      type: 'construct/getConstructorTree'.payload: {
        constructor_type: constructorType}})}useEffect(() => { getConstructorData(); }, [constructorType])

  return (
    <Row style={{marginTop: 24, marginBottom: 24}}>
      <Col span={3}/>
      <Col span={18}>
        <Row>
          <Col span={4}/>
          <Col span={20}>
            <TreeSelect
              allowClear
              showSearch
              style={{width: '100%'}}
              value={searchConstructor}
              filterTreeNode={(inputValue, treeNode) => {
                return treeNode.title.toLowerCase().indexOf(inputValue.toLowerCase()) > -1
              }}
              dropdownStyle={{maxHeight: 600, overflow: 'auto'}}
              treeData={constructorData}
              placeholder="By searching for construction conditions, you can quickly copy parameters oh!"
              treeDefaultExpandAll
              onChange={(e) => {
                save({searchConstructor: e})
                if(e ! = =undefined) {
                  dispatch({
                    type: 'construct/getConstructorData',
                    payload: {id: e.split("_") [1]}})}else {
                  dispatch({
                    type: 'construct/save',
                    payload: {testCaseConstructorData: {type: constructorType, public: true, enable: true}},
                  })
                }
              }}
            />
          </Col>
        </Row>

      </Col>
      <Col span={3}/>
    </Row>

  )}export default connect(({loading, construct}) => ({loading, construct})) (CopyTreeSelect);

Copy the code

Separate this component out into a copy component. And automatically change the data source when the precondition type changes.

A few more tweaks on the page and you’re done. To tell the truth, this piece is a bit bloated, because I can’t see it, so I let go of myself first, but also let go of everyone.

In the next section, let’s take a stab at writing a simple test report email notification feature. (In fact, simple is not simple, if you want to design the style, but also very troublesome)