• whois 看一级域名貌似是个专门刷关键字的

  • app 登入后会有 a、b 两个弹窗...当无法定位的时候 app 自己就跳出了

    这些描述很容易误解,给出两种情况下的控件树和错误日志才能更具体的分析
    猜一下的话driver.findElementById()找不到时会抛异常,需要用 try...catch 控制( 4 楼的方法更好)

    但是根据网络的相应速度 a 、b 两个弹窗的先后次序会变化

    想不出什么样的 App 才需要这样做,问题的确在这吗?

  • Postman 的 Tests 和 Pre-request Script 里都可以使用 CryptoJS 这个库

    //Encode
    var words = CryptoJS.enc.Utf8.parse('Hello CryptoJS');
    var base64 = CryptoJS.enc.Base64.stringify(words);
    console.log(base64);
    
    //Decode
    let parsedWords = CryptoJS.enc.Base64.parse(base64);
    let parsedString = parsedWords.toString(CryptoJS.enc.Utf8);
    console.log(parsedString);
    
  • 然后就了解了 Rails. 才发现别有洞天

    接触 Rails 后发现对设计良好的系统做测试和运维是多么愉快😂

  • 简书文案错误 at June 06, 2017

    "id:"
    "id:"
    "id "
    怎么写都不对,痛苦的回忆

  • 之前 Jenkins Master 在云上,运维帮忙做了端口映射连到内网的 Slave 上的。ngrok 或者 “花生壳” 之类的工具都可以。

  • 试下这三种:

    Thread.sleep(2000);
    WebElement element = driver.findElement(By.xpath(".//html/body/div[1]/nav/div/ul[1]/li/a"));
    System.out.println("Location is: " + element.getLocation());
    
    WebElement element = (new WebDriverWait(driver, 5))
            .until(ExpectedConditions.presenceOfElementLocated(By.xpath(".//html/body/div[1]/nav/div/ul[1]/li/a")));
    System.out.println("Location is: " + element.getLocation());
    
    WebElement element = (new WebDriverWait(driver, 5))
            .until(ExpectedConditions.presenceOfElementLocated(By.xpath(".//img[@alt='480']/parent::a")));
    System.out.println("Location is: " + element.getLocation());
    
  • 不知道你用过这个没? https://jsonschema.net/

  • 装的 Appium Desktop 1.0.0 ,测试机是红米 1s ,Android 4.4

    [Appium] Welcome to Appium v1.6.4
    ...
    [UiAutomator2] UIAutomator2 Driver version:0.3.1

    成功找到 toast 时的 Appium server log:

    [HTTP] --> POST /wd/hub/session/ae9075be-45da-4503-be52-9f1b8cfdc369/element/42777326-5280-41c1-9790-4182a1aba703/click {}
    [MJSONWP] Calling AppiumDriver.click() with args: ["42777326-5280-41c1-9790-4182a1aba703","ae9075be-45da-4503-be52-9f1b8cfdc369"]
    [JSONWP Proxy] Proxying [POST /element/42777326-5280-41c1-9790-4182a1aba703/click] to [POST http://localhost:8222/wd/hub/session/84f012ed-714e-4d4b-bcbf-1d1ec0efe46d/element/42777326-5280-41c1-9790-4182a1aba703/click] with body: {"element":"42777326-5280-41c1-9790-4182a1aba703"}
    [JSONWP Proxy] Got response with status 200: {"value":true,"status":0,"sessionId":"84f012ed-714e-4d4b-bcbf-1d1ec0efe46d"}
    [MJSONWP] Responding to client with driver.click() result: true
    [HTTP] <-- POST /wd/hub/session/ae9075be-45da-4503-be52-9f1b8cfdc369/element/42777326-5280-41c1-9790-4182a1aba703/click 200 252 ms - 76 
    [HTTP] --> POST /wd/hub/session/ae9075be-45da-4503-be52-9f1b8cfdc369/element {"using":"xpath","value":".//*[contains(@text, \"toast\")]"}
    [MJSONWP] Calling AppiumDriver.findElement() with args: ["xpath",".//*[contains(@text, \"toast\")]","ae9075be-45da-4503-be52-9f1b8cfdc369"]
    [BaseDriver] Valid locator strategies for this request: xpath, id, class name, accessibility id, -android uiautomator
    [BaseDriver] Valid locator strategies for this request: xpath, id, class name, accessibility id, -android uiautomator
    [BaseDriver] Waiting up to 0 ms for condition
    [JSONWP Proxy] Proxying [POST /element] to [POST http://localhost:8222/wd/hub/session/84f012ed-714e-4d4b-bcbf-1d1ec0efe46d/element] with body: {"strategy":"xpath","selector":".//*[contains(@text, \"toast\")]","context":"","multiple":false}
    [JSONWP Proxy] Got response with status 200: {"value":{"ELEMENT":"1f60e7a9-3fa5-4b9f-92e4-c060a019e3b9"},"status":0,"sessionId":"84f012ed-714e-4d4b-bcbf-1d1ec0efe46d"}
    [MJSONWP] Responding to client with driver.findElement() result: {"ELEMENT":"1f60e7a9-3fa5-4b9f-92e4-c060a019e3b9"}
    [HTTP] <-- POST /wd/hub/session/ae9075be-45da-4503-be52-9f1b8cfdc369/element 200 94 ms - 122 
    [HTTP] --> GET /wd/hub/session/ae9075be-45da-4503-be52-9f1b8cfdc369/element/1f60e7a9-3fa5-4b9f-92e4-c060a019e3b9/attribute/text {}
    [MJSONWP] Calling AppiumDriver.getAttribute() with args: ["text","1f60e7a9-3fa5-4b9f-92e4-c060a019e3b9","ae9075be-45da-4503-be52-9f1b8cfdc369"]
    [JSONWP Proxy] Proxying [GET /element/1f60e7a9-3fa5-4b9f-92e4-c060a019e3b9/attribute/text] to [GET http://localhost:8222/wd/hub/session/84f012ed-714e-4d4b-bcbf-1d1ec0efe46d/element/1f60e7a9-3fa5-4b9f-92e4-c060a019e3b9/attribute/text] with body: {}
    [JSONWP Proxy] Got response with status 200: "{\"value\":\"Hello toast!\",\"status\":0,\"sessionId\":\"84f012ed-714e-4d4b-bcbf-1d1ec0efe46d\"}"
    [MJSONWP] Responding to client with driver.getAttribute() result: "Hello toast!"
    [HTTP] <-- GET /wd/hub/session/ae9075be-45da-4503-be52-9f1b8cfdc369/element/1f60e7a9-3fa5-4b9f-92e4-c060a019e3b9/attribute/text 200 114 ms - 86 
    

    直接发 HTTP 请求吧

    # 点击按钮触发 toast 
    curl -X POST --header "Accept:application/json" --header "Content-Type: application/json; charset=utf-8" --data "{}" http://127.0.0.1:4723/wd/hub/session/${session}/element/${toast_button}/click
    
    # 查找 toast ,toast 还没消失的时候才能找到
    curl -X POST --header "Accept:application/json" --header "Content-Type: application/json; charset=utf-8" --data "{\"using\":\"xpath\",\"value\":\".//*[contains(@text, \\\"toast\\\")]\"}" http://127.0.0.1:4723/wd/hub/session/${session}/element
    
    # 获取 toast 的内容
    curl -X GET --header "Accept:application/json" --header "Content-Type: application/json; charset=utf-8" http://127.0.0.1:4723/wd/hub/session/${session}/element/${toast}/attribute/text
    
  • 见过不少方案,如果让客户端升级,有:

    1. 运营手段,比如新版本才能领红包。
    2. 客户端能做到功能之间隔离,用到不兼容的功能时才会提示需要升级。
    3. 热更新。

    这其实也是 Hybird 的价值之一,易变的部分用 Web 。

    API 版本号,加在不同地方对于开发、测试、运维的影响也会不一样:

    http://host/version3/api
    
    http://host/api?version=3
    
    GET /api HTTP/1.1
    Accept: application/version3
    
    GET /api HTTP/1.1
    
    {
      "version": 3
    }
    
  • 没留视频,bilibili 上视频都有办法下载的,可以搜下。

  • 数据库冗余有时候是为了提高查询速度,我碰到的那种冗余想不到会有什么好处,所以还是得具体分析。

  • ios-webkit-debug-proxy.md
    iwd_xcode7.md
    

    @Lihuazhang 这两个没人领的话我就领了,这帖子已经很难看懂了,光把没完成的列在开头吧?

  • 具体到这个问题,表述的过于简单了,开始只有 “冗余会在未来坑你” 这个想法,找相关同事讨论了下,设想了几个可能被坑的场景之后才提的。提了之后开发那意见也不一致,不过这个问题最后是改了,其他问题也有碰到最后不改的。
    有 “代码洁癖” 的人也有,这时候也不用费劲去设想那个会有严重后果的场景了。

  • 之前有次经历还有印象:
    有时候在 Web 上正常操作会碰到 CRSF 错误和 Cookie 过期两个问题,没找到稳定重现方法。
    想了想 CRSF 的原因,觉得可能和多浏览器,多标签,多终端有关,按这个思路测试,仍然没重现,却发现三个其他功能点在这种场景下的缺陷。
    那先查 Cookie 过期吧,想到 App 没有碰到同样的问题,仔细对比在 Web 和 App 上登录状态有关的请求,对着文档一个字段一个字段看,发现登录请求中有个字段没有必要再使用了,在新的系统设计里虽然没有直接害处,但本着 “冗余会在未来坑你” 的想法也提了个缺陷。
    对着两边的抓包记录,注意到 Web 比 App 多了 longpulling,每个浏览器标签有一个,而且响应时间不稳定,有时会超过 5 秒。联想到异步,两个标签,在这 5 秒内一个退出登录会怎么样?
    之后重现了一个问题,开发同事修复的时候发现另一个也是同样的原因,取决于两个异步请求处理的先后。
    还没完,退出登录很少被用到,所以过期时间的功能可能有问题……

  • 够用就好,喜欢用 JSON Schema 也是因为可以配合 Swagger 、RAML 这种 API 文档。
    这样看起来 rest-assured 很不错,如果下份工作不得不用 Java 就去看看😳

  • JSON 有结构描述规范 JSON Schema
    比如 Ruby 有 json-schema 这个库实现了 JSON Schema 规范,可以用来验证 JSON 结构,搜了下 Java 也有好几个实现

    require "json-schema”
    
    valid_json = '{
                    "location": "home",
                    "code": 44
                  }'
    invalid_type_json = '{
                            "location": "home",
                            "code": "44"
                         }'
    
    missing_properties_json = '{
                                  "location": "home"
                               }'
    
    schema = '{
                "$schema": "http://json-schema.org/draft-04/schema#",
                "type": "object",
                "properties": {
                  "location": {
                    "type": "string"
                  },
                  "code": {
                    "type": "integer"
                  }
                },
                "required": [
                  "location",
                  "code"
                ]
              }'
    
    JSON::Validator.validate!(schema, valid_json) # 返回 true
    JSON::Validator.validate!(schema, invalid_type_json) # 抛出异常 The property '#/code' of type String did not match the following type: integer
    JSON::Validator.validate!(schema, missing_properties_json) # 抛出异常 The property '#/' did not contain a required property of 'code'
    
    
  • 请问接口测试数据来源 at February 22, 2017

    #15 楼 @ycwdaaaa 不少 APP 上都见过这种啦

  • Spawning processes from build
    Shell 启动 appium --session-override -a xx.xx.xx -p 1234,在你 ctrl + c 之前,这个进程一直存活,所以 Jenkins 上这个 Job 一直不会结束。解决方法上面的链接也有。

  • 看看这个:
    Starting Appium fails on Android N (Nougat)

    试下在模拟器上能装上输入法吗?

    adb uninstall io.appium.android.ime
    adb install D:\Test
    ing\AppiumForWindows_1_4_16_1\Appium\node_modules\appium\build\unicode_ime_apk\U
    nicodeIME-debug.apk
    
  • 在几个比较活跃的游戏策划群里,以前经常看他们聊天。有次印象很深,有个数值策划大概是这么说的:“有些 Excel 表写个简单的 VBA ,很快就填完了,有些人就要手填,培训也不学。”

    自己是文科生,也实在对代码无爱

    另一句印象深刻的话

    所谓 “偏见”,就是节省认知成本的规则。虽然,“没有免费午餐”。

    我觉得你已经踏在管理的门边了。

  • 排下版吧,内容挺好的。

  • #113 楼 @Lihuazhang
    给个例子?有啥格式要求之类的吗

  • 安装 appium for mac 卡住了 at February 07, 2017

    cnpm只解决npm相关的**、慢的问题,github 上的东西还是有问题,用 ** 或代理吧。