使用ReactJS+babel+Bulma CSS构建测试报告页面

测试过程中,会有需要将Test Report以各种样式呈现的需求。
本例使用ReactJS + babel + Bulma CSS呈现带菜单和分类的静态测试报告页面。
这种方式可以使数据和报告分离。
使用不同的data.js文件,可以展示不同的测试报告。
程序输出的样例报告效果如下,


image.png

程序代码如下,
index.html

<!DOCTYPE html>  
<html lang="en">  
<head>  
    <meta charset="UTF-8">  
    <title>Bifang工程测试报告</title>  
    <script src="./src/lib/react-development.js"></script>
    <script src="./src/lib/react-dom.development.js"></script> 
    <script src="./src/lib/babel.min.js"></script>  
    <link rel="stylesheet" href="./css/bulma/bulma.min.css">
</head>  
<body>  
    <div id="main"></div>

    <script src="./data.js" type="text/javascript"></script>
    <script type="text/babel">  

        class ChannelInfo extends React.Component {
            constructor(props) {
                super(props)
            }
            
            render() {
                return (<div>
                    <table className="table" border={0} style={ {width: "100%"} }>
                            <tbody>
                                <tr>
                                    <th> topic name </th>
                                    <td>{this.props.channel["topic_name"]}</td>
                                </tr>
                             
                                <tr>
                                    <th> Messages </th>
                                    <td>
                                        <ul>
                                            {this.props.channel["messages"].map(
                                                (msg, i) =>
                                                <li key={i}>
                                                    <span className="subtitle is-6"> 
                                                        {JSON.stringify(msg)}
                                                    </span>
                                                </li>
                                            )}
                                        </ul>
                                    </td>
                                </tr>

                            </tbody>
                    </table>
                </div>)
            }

        }



        class PageContent extends React.Component {
            constructor(props) {
                super(props)
                this.state = {
                    display: false
                }
            }

            setDisplay() {
                this.setState({display: !this.state.display})
            }

            render() {
                return (<div className="block">
                            <div onClick={() => this.setDisplay()}>
                                <table class="table">
                                    <tr>
                                        <td><abbr title="Position">{this.props.content["descriptions"]["case_id"]}.</abbr></td>
                                        <td>{this.props.content["descriptions"]["case_name"]}</td>
                                    </tr>
                                </table>
                            </div>

                            <h2 className="is-5" style={this.state.display? {}: {display: "none"}}>
                                <table className="table">
                                    <thead>
                                        <tr>
                                            <th><abbr title="Title">Title</abbr></th>
                                            <th>Content</th>
                                        </tr>
                                    </thead>
                                    
                                    <tbody>
                                        <tr>
                                            <th>Description</th>
                                            <td>
                                                <li> Test Case ID : { this.props.content["descriptions"]["case_id"] } </li>
                                                <li> Case Name : { this.props.content["descriptions"]["case_name"]} </li>
                                                <li> Validation Type: { this.props.content["validate_type"] } </li>
                                            </td>
                                        </tr>

                                        <tr>
                                            <th>Passed</th>
                                            {this.props.content["passed"]? 
                                                <td className="is-success"> Yes </td>: 
                                                <td className="is-danger"> NO </td>
                                            }
                                        </tr>


                                        <tr>
                                        <th> Input Messages </th>
                                        {
                                            
                                            this.props.content["input"].map(
                                            (channel, i) =>
                                                <tr>
                                                    <td key={i}><ChannelInfo channel={channel} /></td>
                                                </tr>
                                            )
                                        }
                                        </tr>

                                        <tr>
                                        <th> Output Messages </th>
                                        {
                                            
                                            this.props.content["actual"].map(
                                            (channel, i) =>
                                                <tr>
                                                    <td key={i}><ChannelInfo channel={channel} /></td>
                                                </tr>
                                            )
                                        }
                                        </tr>


                                        <tr>
                                        <th> Expect Messages </th>
                                        {
                                            
                                            this.props.content["expectation"].map(
                                            (channel, i) =>
                                                <tr>
                                                    <td key={i}><ChannelInfo channel={channel} /></td>
                                                </tr>
                                            )
                                        }
                                        </tr>

                                        <tr>
                                            <th>
                                                Test Result
                                            </th>
                                            <td>
                                                <span className="subtitle is-6" dangerouslySetInnerHTML={{__html: this.props.content["result_info"].replace("\n", "<p>")}} />
                                            </td>
                                        </tr>
                                        
                                   
                                    </tbody>
                                
                                </table>
                            </h2>

                    </div>)   
            }
        }

        class MainPage extends React.Component {
            constructor(props) {
                super(props)
                console.log("DATA==")
                console.log(this.props.data)
                this.state = {
                    case_st: "FAIL",
                    page: "UIUE"
                }
            }

            setPage = (page_) => {
                this.setState({page: page_})
            }

            setCaseStatus= (status_) => {
                console.log("Set case Status!")
                this.setState({case_st: status_})
            }

            renderHeader = () => {
               
                if(this.state.page && this.props.data.hasOwnProperty(this.state.page)) {
                        return (
                        <div className="tile is-ancestor columns">
                            <div className="tile is-parent column is-4">
                                <article className={this.state.case_st === "FAIL"? "tile is-child notification is-danger": "tile is-child notification" }  onClick={() => this.setCaseStatus("FAIL")}>
                                
                                <p className="subtitle">FAILED</p>
                                <p className="subtitle">{this.props.data[this.state.page]["failed"]}</p>
                                </article>
                            </div>
                        
                                <div className="tile is-parent column is-4">
                                    <article className={this.state.case_st === "PASS"? "tile is-child notification is-danger": "tile is-child notification" }  onClick={()=>this.setCaseStatus("PASS")}>
                                    <p className="subtitle">Passed</p>
                                    <p className="subtitle">{this.props.data[this.state.page]["passed"]}</p>
                                    </article>
                                </div>
                        
                            <div className="tile is-parent column is-4">
                                <article className="tile is-child notification">
                                <p className="subtitle">Pass Rate</p>
                                <p className="subtitle">{this.props.data[this.state.page]["pass_rate"]}</p>
                                </article>
                            </div>
                    </div>
                    )
                }   
            }

            renderBody = (bodyData) => {
                    return (<div className="block">
                            {bodyData.map((test_case, i) =>
                                <PageContent key={i} content={test_case} />
                            )}
                        </div>
                    )   
            }


            render() {

                return (
                    
                <div className="columns">
                <div className="column is-2">
                            <div className="block">
                                <aside className="menu">
                                    <p className="menu-label">测试报告</p>
                                    <ul className="menu-list">
                                        <li> <a onClick={() => this.setPage("UIUE")} className={this.state.page === "UIUE" ? "is-active": ""}>UIUE模块</a></li>
                                        <li> <a onClick={() => this.setPage("ParkingFus")} className={this.state.page === "ParkingFus" ? "is-active": ""}>ParkingFus模块</a></li>
                                    </ul>
                                </aside>
                        </div>
                    </div>
                    
                    <div className="block column is-9">
                        {this.renderHeader()}
                        {  
                            this.state.case_st === "FAIL" ? this.renderBody(this.props.data[this.state.page]["failed_cases"]):
                             this.renderBody(this.props.data[this.state.page]["passed_cases"])
                        }
                    </div>
                </div>
                )
            }
        }

        class App extends React.Component {
            constructor(props) {
                super(props)
            }

            render() {
                return (<div className="container" >
                          <MainPage data={this.props.data}/>            
                    </div>)
            }
        }

        ReactDOM.render(
            <App data={js_obj}/>,
            document.getElementById('main')
        );
    </script>
</body>  
</html>

data.js文件如下,

let js_obj = {
    "ParkingFus": {
        "passed_cases": [
            {
                "passed": true,
                "descriptions": {
                    "case_id": 1,
                    "case_name": "ParkingFus全景开启,软按键开启"
                },
                "input": [
                    {
                        "topic_name": "Send_Topic_name",
                        "messages": [
                            {
                                "struct": "SendCSC_APA_Req_Fusion_Struct",
                                "Get_Something_uint8": 1
                            },
                            {
                                "struct": "SendVDL_APA_Req_Fusion_Struct",
                                "Set_Something_uint8": 2
                            }
                        ]
                    },
                    {
                        "topic_name": "Send_Topic_name_2",
                        "messages": [
                            {
                                "struct": "SendCSC_APA_Req_Fusion_Struct",
                                "Get_Something_uint8": 3
                            },
                            {
                                "struct": "SendVDL_APA_Req_Fusion_Struct",
                                "Set_Something_uint8": 4
                            }
                        ]
                    }
                ],
                "validate_type": "log|msg",
                "expectation": [
                    {
                        "topic_name": "Rec_Topic_name",
                        "messages": [
                            {
                                "struct": "RecvCSC_APA_Req_Fusion_Struct",
                                "Get_Something_uint8": 1
                            },
                            {
                                "struct": "RecvVDL_APA_Req_Fusion_Struct",
                                "Set_Something_uint8": 2
                            }
                        ]
                    },
                    {
                        "topic_name": "Rec_Topic_name_2",
                        "messages": [
                            {
                                "struct": "RecvCSC_APA_Req_Fusion_Struct",
                                "Get_Something_uint8": 3
                            },
                            {
                                "struct": "RecvVDL_APA_Req_Fusion_Struct",
                                "Set_Something_uint8": 4
                            }
                        ]
                    }
                ],
                "actual": [
                    {
                        "topic_name": "Rec_Topic_name",
                        "messages": [
                            {
                                "struct": "RecvCSC_APA_Req_Fusion_Struct",
                                "Get_Something_uint8": 1
                            },
                            {
                                "struct": "RecvVDL_APA_Req_Fusion_Struct",
                                "Set_Something_uint8": 2
                            }
                        ]
                    },
                    {
                        "topic_name": "Rec_Topic_name_2",
                        "messages": [
                            {
                                "struct": "RecvCSC_APA_Req_Fusion_Struct",
                                "Get_Something_uint8": 3
                            },
                            {
                                "struct": "RecvVDL_APA_Req_Fusion_Struct",
                                "Set_Something_uint8": 4
                            }
                        ]
                    }
                ],
                "result_info": "Msg equal passed\nLog equal passed\n"
            }
        ],
        "failed_cases": [
            {
                "passed": false,
                "descriptions": {
                    "case_id": 2,
                    "case_name": "ParkingFus全景开启,软按键开启"
                },
                "input": [
                    {
                        "topic_name": "Send_Topic_name",
                        "messages": [
                            {
                                "struct": "SendCSC_APA_Req_Fusion_Struct",
                                "Get_Something_uint8": 1
                            },
                            {
                                "struct": "SendVDL_APA_Req_Fusion_Struct",
                                "Set_Something_uint8": 2
                            }
                        ]
                    },
                    {
                        "topic_name": "Send_Topic_name_2",
                        "messages": [
                            {
                                "struct": "SendCSC_APA_Req_Fusion_Struct",
                                "Get_Something_uint8": 3
                            },
                            {
                                "struct": "SendVDL_APA_Req_Fusion_Struct",
                                "Set_Something_uint8": 4
                            }
                        ]
                    }
                ],
                "validate_type": "log|msg",
                "expectation": [
                    {
                        "topic_name": "Rec_Topic_name",
                        "messages": [
                            {
                                "struct": "RecvCSC_APA_Req_Fusion_Struct",
                                "Get_Something_uint8": 3
                            },
                            {
                                "struct": "RecvVDL_APA_Req_Fusion_Struct",
                                "Set_Something_uint8": 2
                            }
                        ]
                    },
                    {
                        "topic_name": "Rec_Topic_name_2",
                        "messages": [
                            {
                                "struct": "RecvCSC_APA_Req_Fusion_Struct",
                                "Get_Something_uint8": 3
                            },
                            {
                                "struct": "RecvVDL_APA_Req_Fusion_Struct",
                                "Set_Something_uint8": 4
                            }
                        ]
                    }
                ],
                "actual": [
                    {
                        "topic_name": "Rec_Topic_name",
                        "messages": [
                            {
                                "struct": "RecvCSC_APA_Req_Fusion_Struct",
                                "Get_Something_uint8": 1
                            },
                            {
                                "struct": "RecvVDL_APA_Req_Fusion_Struct",
                                "Set_Something_uint8": 2
                            }
                        ]
                    },
                    {
                        "topic_name": "Rec_Topic_name_2",
                        "messages": [
                            {
                                "struct": "RecvCSC_APA_Req_Fusion_Struct",
                                "Get_Something_uint8": 3
                            },
                            {
                                "struct": "RecvVDL_APA_Req_Fusion_Struct",
                                "Set_Something_uint8": 4
                            }
                        ]
                    }
                ],
                "result_info": "Msg equal passed\nLog equal passed\n"
            }
        ],
        "passed": 1,
        "failed": 1,
        "pass_rate": "50.0%"
    },
    "UIUE": {
        "passed_cases": [
            {
                "passed": true,
                "descriptions": {
                    "case_id": 1,
                    "case_name": "UIUE全景开启,软按键开启"
                },
                "input": [
                    {
                        "topic_name": "Send_Topic_name",
                        "messages": [
                            {
                                "struct": "SendCSC_APA_Req_Fusion_Struct",
                                "Get_Something_uint8": 1
                            },
                            {
                                "struct": "SendVDL_APA_Req_Fusion_Struct",
                                "Set_Something_uint8": 2
                            }
                        ]
                    },
                    {
                        "topic_name": "Send_Topic_name_2",
                        "messages": [
                            {
                                "struct": "SendCSC_APA_Req_Fusion_Struct",
                                "Get_Something_uint8": 3
                            },
                            {
                                "struct": "SendVDL_APA_Req_Fusion_Struct",
                                "Set_Something_uint8": 4
                            }
                        ]
                    }
                ],
                "validate_type": "log|msg",
                "expectation": [
                    {
                        "topic_name": "Rec_Topic_name",
                        "messages": [
                            {
                                "struct": "RecvCSC_APA_Req_Fusion_Struct",
                                "Get_Something_uint8": 1
                            },
                            {
                                "struct": "RecvVDL_APA_Req_Fusion_Struct",
                                "Set_Something_uint8": 2
                            }
                        ]
                    },
                    {
                        "topic_name": "Rec_Topic_name_2",
                        "messages": [
                            {
                                "struct": "RecvCSC_APA_Req_Fusion_Struct",
                                "Get_Something_uint8": 3
                            },
                            {
                                "struct": "RecvVDL_APA_Req_Fusion_Struct",
                                "Set_Something_uint8": 4
                            }
                        ]
                    }
                ],
                "actual": [
                    {
                        "topic_name": "Rec_Topic_name",
                        "messages": [
                            {
                                "struct": "RecvCSC_APA_Req_Fusion_Struct",
                                "Get_Something_uint8": 1
                            },
                            {
                                "struct": "RecvVDL_APA_Req_Fusion_Struct",
                                "Set_Something_uint8": 2
                            }
                        ]
                    },
                    {
                        "topic_name": "Rec_Topic_name_2",
                        "messages": [
                            {
                                "struct": "RecvCSC_APA_Req_Fusion_Struct",
                                "Get_Something_uint8": 3
                            },
                            {
                                "struct": "RecvVDL_APA_Req_Fusion_Struct",
                                "Set_Something_uint8": 4
                            }
                        ]
                    }
                ],
                "result_info": "Msg equal passed\nLog equal passed\n"
            }
        ],
        "failed_cases": [
            {
                "passed": false,
                "descriptions": {
                    "case_id": 2,
                    "case_name": "UIUE全景开启,软按键开启"
                },
                "input": [
                    {
                        "topic_name": "Send_Topic_name",
                        "messages": [
                            {
                                "struct": "SendCSC_APA_Req_Fusion_Struct",
                                "Get_Something_uint8": 1
                            },
                            {
                                "struct": "SendVDL_APA_Req_Fusion_Struct",
                                "Set_Something_uint8": 2
                            }
                        ]
                    },
                    {
                        "topic_name": "Send_Topic_name_2",
                        "messages": [
                            {
                                "struct": "SendCSC_APA_Req_Fusion_Struct",
                                "Get_Something_uint8": 3
                            },
                            {
                                "struct": "SendVDL_APA_Req_Fusion_Struct",
                                "Set_Something_uint8": 4
                            }
                        ]
                    }
                ],
                "validate_type": "log|msg",
                "expectation": [
                    {
                        "topic_name": "Rec_Topic_name",
                        "messages": [
                            {
                                "struct": "RecvCSC_APA_Req_Fusion_Struct",
                                "Get_Something_uint8": 3
                            },
                            {
                                "struct": "RecvVDL_APA_Req_Fusion_Struct",
                                "Set_Something_uint8": 2
                            }
                        ]
                    },
                    {
                        "topic_name": "Rec_Topic_name_2",
                        "messages": [
                            {
                                "struct": "RecvCSC_APA_Req_Fusion_Struct",
                                "Get_Something_uint8": 3
                            },
                            {
                                "struct": "RecvVDL_APA_Req_Fusion_Struct",
                                "Set_Something_uint8": 4
                            }
                        ]
                    }
                ],
                "actual": [
                    {
                        "topic_name": "Rec_Topic_name",
                        "messages": [
                            {
                                "struct": "RecvCSC_APA_Req_Fusion_Struct",
                                "Get_Something_uint8": 1
                            },
                            {
                                "struct": "RecvVDL_APA_Req_Fusion_Struct",
                                "Set_Something_uint8": 2
                            }
                        ]
                    },
                    {
                        "topic_name": "Rec_Topic_name_2",
                        "messages": [
                            {
                                "struct": "RecvCSC_APA_Req_Fusion_Struct",
                                "Get_Something_uint8": 3
                            },
                            {
                                "struct": "RecvVDL_APA_Req_Fusion_Struct",
                                "Set_Something_uint8": 4
                            }
                        ]
                    }
                ],
                "result_info": "Msg equal passed\nLog equal passed\n"
            }
        ],
        "passed": 1,
        "failed": 1,
        "pass_rate": "50.0%"
    }
}

其中使用的react-development.js,react-dom.development.js, babel.min.js和bulma.min.css可以到网上进行下载。是通用的css和js文件。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,242评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,769评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,484评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,133评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,007评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,080评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,496评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,190评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,464评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,549评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,330评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,205评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,567评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,889评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,160评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,475评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,650评论 2 335

推荐阅读更多精彩内容