zoukankan      html  css  js  c++  java
  • 用C#在Visual Studio写Javascript单元测试(Firefox内核)

    引用nuget包:

    注意:Geckofx45 nuget包必须是最后引用,否则初始化会出错

    编写JsRunner

    using Gecko;
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace Way.UnitTest
    {
        class JsRunner:IDisposable
        {
            static JsRunner()
            {
                Xpcom.Initialize("Firefox");
            }
    
            static List<JsFileReference> ReferenceConfigs = new List<JsFileReference>();
            static List<string> GlobalJSFiles = new List<string>();
            /// <summary>
            /// 设置js文件依赖
            /// </summary>
            /// <param name="jsFile">js文件路径</param>
            /// <param name="references">所依赖的js文件路径</param>
            public static void SetJsReference(string jsFile,IEnumerable<string> references)
            {
                ReferenceConfigs.Add(new JsFileReference() {
                    JsFile = jsFile,
                    References = references,
                });
            }
            /// <summary>
            /// 添加全局js文件
            /// </summary>
            /// <param name="jsFile"></param>
            public static void AddGlobalJsFile(string jsFile)
            {
                GlobalJSFiles.Add(jsFile);
            }
    
            public JsRunner()
            {
                JsFiles.AddRange(GlobalJSFiles);
            }
            ~JsRunner()
            {
                Dispose();
            }
            List<string> JsFiles = new List<string>();
            /// <summary>
            /// 添加js文件
            /// </summary>
            /// <param name="jsPath">js文件路径</param>
            public void AddJsFile(string jsPath)
            {
                putJsFileContentToList(jsPath);
               
            }
            
            void putJsFileContentToList(string jsPath)
            {
                if (JsFiles.Contains(jsPath) )
                {
                    return;
                }
                //查找该js是否引用其他js
                var arr = ReferenceConfigs.Where(m => string.Equals(m.JsFile, jsPath, StringComparison.CurrentCultureIgnoreCase));
                foreach( var item in arr )
                {
                    foreach( var path in item.References )
                    {
                        putJsFileContentToList(path);
                    }
                }
                JsFiles.Add(jsPath);
            }
    
           
    
            /// <summary>
            /// 运行js代码
            /// </summary>
            /// <typeparam name="T">返回值类型</typeparam>
            /// <param name="jsCode">一段js代码。如:return data.name;</param>
            /// <param name="data">传到js里面的对象,js可以通过data.*直接使用此参数</param>
            /// <returns></returns>
            public T Run<T>(string jsCode, object data)
            {
                var gecko = new GeckoWebBrowser();
                gecko.CreateControl();bool loadFinished = false;
    
                gecko.NavigationError += (s, e) =>
                {
                };
                gecko.NSSError += (s, e) =>
                {
                };
                gecko.DocumentCompleted += (s, e) => {
                    loadFinished = true;
                };
                string tempFileName = System.IO.Path.GetTempFileName();
                System.IO.StreamWriter sw = new StreamWriter(System.IO.File.OpenWrite(tempFileName));
                
                sw.WriteLine("<!DOCTYPE html>");
                sw.WriteLine("<html>");
                foreach (var path in JsFiles)
                {
                    sw.WriteLine("<script src="file:///" + path + "" type="text/javascript"></script>");
                }            
                sw.WriteLine("<body>");
                
                sw.WriteLine("<input type=hidden id='inputResult'>");
                sw.WriteLine("<input type=hidden id='inputError'>");
                sw.WriteLine("</body>");
                sw.WriteLine("</html>");
                sw.Dispose();
    
                gecko.Navigate("file:///" + tempFileName);
    
                while (!loadFinished)
                {
                    System.Threading.Thread.Sleep(10);
                    System.Windows.Forms.Application.DoEvents();
                }
                System.IO.File.Delete(tempFileName);
    
                var jsContext = new AutoJSContext(gecko.Window);
               
    
                var js = @"
    (function(d){
        try{
            var result = (function(data){" + jsCode + @"})(d);
            return JSON.stringify(result);
        }catch(e)
        {
            if(typeof e == 'string')
                return JSON.stringify({ ______err : e , line:0 });
            else
                return JSON.stringify({ ______err : e.message , line:e.lineNumber });
        }
    })(" + (data == null ? "null" : Newtonsoft.Json.JsonConvert.SerializeObject(data)) + @");
    ";
    
                string result;
                jsContext.EvaluateScript(js, out result);
                jsContext.Dispose();
                gecko.Dispose();
    
                if(result.StartsWith("{"______err":"))
                {
                   var errObj =  Newtonsoft.Json.JsonConvert.DeserializeObject<Newtonsoft.Json.Linq.JObject>(result);
                    string errMsg = errObj.Value<string>("______err");
                    //int lineNumber = errObj.Value<int>("line") - 3;
                    throw new Exception(errMsg);
                }
                return Newtonsoft.Json.JsonConvert.DeserializeObject<T>(result);
            }
    
            /// <summary>
            /// 读取js文件内容
            /// </summary>
            /// <param name="filePath"></param>
            /// <returns></returns>
            string readJsFile(string filePath)
            {
                using (System.IO.FileStream fs = System.IO.File.OpenRead(filePath))
                {
                    var data = new byte[fs.Length];
                    var isUtf8 = IsUTF8(fs);
                    fs.Position = 0;
                    fs.Read(data, 0, data.Length);
                    if (isUtf8)
                    { 
                        return Encoding.UTF8.GetString(data);
                    }
                    else
                    {
                        return Encoding.GetEncoding("gb2312").GetString(data);
                    }
                }
            }
    
            /// <summary>
            /// 判断流是否是utf-8编码
            /// </summary>
            /// <param name="stream"></param>
            /// <returns></returns>
            static bool IsUTF8(Stream stream)
            {
                bool IsUTF8 = true;
    
                while (stream.Position < stream.Length)
                {
                    byte b = (byte)stream.ReadByte();
                    if (b < 0x80) // (10000000): 值小于0x80的为ASCII字符    
                    {
    
                    }
                    else if (b < (0xC0)) // (11000000): 值介于0x80与0xC0之间的为无效UTF-8字符    
                    {
                        IsUTF8 = false;
                        break;
                    }
                    else if (b < (0xE0)) // (11100000): 此范围内为2字节UTF-8字符    
                    {
                        if (stream.Position >= stream.Length - 1)
                        {
                            break;
                        }
                        byte nextByte = (byte)stream.ReadByte();
                        if ((nextByte & (0xC0)) != 0x80)
                        {
                            IsUTF8 = false;
                            break;
                        }
                    }
                    else if (b < (0xF0)) // (11110000): 此范围内为3字节UTF-8字符    
                    {
                        if (stream.Position >= stream.Length - 2)
                        {
                            break;
                        }
    
                        byte nextByte1 = (byte)stream.ReadByte();
                        byte nextByte2 = (byte)stream.ReadByte();
                        if ((nextByte1 & (0xC0)) != 0x80 || (nextByte2 & (0xC0)) != 0x80)
                        {
                            IsUTF8 = false;
                            break;
                        }
                    }
                    else
                    {
                        IsUTF8 = false;
                        break;
                    }
                }
    
                return IsUTF8;
    
            }
    
            public void Dispose()
            {
                JsFiles.Clear();
            }
        }
    
        class JsFileReference
        {
            /// <summary>
            /// js文件
            /// </summary>
            public string JsFile;
            /// <summary>
            /// 所依赖的js文件
            /// </summary>
            public IEnumerable<string> References;
            
        }
    
    }

    编写单元测试基类

    using System;
    using Microsoft.VisualStudio.TestTools.UnitTesting;
    using Gecko;
    
    namespace Way.UnitTest.Javascript
    {
        /// <summary>
        /// 其他js单元测试,建议继承此类
        /// </summary>
        [TestClass]
        public class JSUnitTest
        {
    
            static JSUnitTest()
            {
                Xpcom.Initialize("Firefox");
               
    
                //组合文件夹路径
                var solutionPath = AppDomain.CurrentDomain.BaseDirectory + "\..\..\..\";
    
                //添加全局使用的js文件
                JsRunner.AddGlobalJsFile($"{solutionPath}\js\xpos-10.core.js");
    
    
                //定义js文件的依赖关系,这里只是举例,文件实际不存在
                //设置kkk.js依赖于a1.js  a2.js 两个文件,
                //这样,每当使用kkk.js文件,系统会自动引入a1.js  a2.js 两个文件
                JsRunner.SetJsReference($"{solutionPath}\kkk.js", new string[] {
                    //这里写上所依赖js文件的路径
                    $"{solutionPath}\a1.js",
                    $"{solutionPath}\a2.js"
                });
    
            }
                  
        }
    }

    编写测试代码

    using System;
    using Microsoft.VisualStudio.TestTools.UnitTesting;
    
    namespace Way.UnitTest.Javascript
    {
        [TestClass]
        public class Example : JSUnitTest
        {
    
            [TestMethod]
            public void Test()
            {
                using (JsRunner jsEngine = new JsRunner())
                {
                    //编写js代码
                    var js = @"
    return data.name;
    ";
                    //运行js代码
                    var result = jsEngine.Run<string>(js, new {name="JACK"});
                    if (result != "JACK")
                        throw new Exception("运算结果错误");
                }
            }
    
        }
    }
  • 相关阅读:
    SQLServer 使用ADSI执行分布式查询ActiveDorectory对象
    GridView的DataFormatString
    我的第一篇博客
    delphi for php 帮助文档的笔记(二)
    用delphiforphp来编写算法注册机第一节
    delphiforphp的中文环境的搭建
    初步拟定的delphiforphp的学习计划
    取當前日期各种數据庫的寫法(转存,备查)
    php两页间传变量(转发,备查)
    关于delphiforphp我想说的。
  • 原文地址:https://www.cnblogs.com/IWings/p/8565318.html
Copyright © 2011-2022 走看看