如何使用碎片化文档验证 graphql 模式

Posted

技术标签:

【中文标题】如何使用碎片化文档验证 graphql 模式【英文标题】:How to validate graphql schema with fragmented documents 【发布时间】:2020-05-09 05:59:43 【问题描述】:

我认为在单元测试级别支持架构验证会很酷,这样我们就可以在升级 api 时意识到对查询的重大更改

我想设置测试,以便它支持自动发现任何新的 *.graphql 文件,但这样做,开玩笑的过程认为当前工作目录在 __tests__ 所以当我评估 graphql使用加载器手动记录文档,这样的查询中的相关片段失败:

#import "./fragments/FullUserData.graphql"

query User(
  $zid: String!
) 
  user 
    userData: get(
      zid: $zid
    ) 
      ...FullUserData
    
  

失败信息:

Error: Cannot find module './fragments/FullUserData.graphql' from 'schemaValidation-test.js'"

如果我将 Fragments 文件夹移动到 __tests__ 目录中,则测试会很顺利。 关于我可以做些什么来欺骗评估以处理片段的任何想法,就好像我是相对于片段目录一样?

__tests__/
  - schemaValidation-test.js
queries/
  - someQuery.graphql
  - fragments/someFragment.graphql

我在 jest 中尝试了 process.chdir() 到查询目录,但没有骰子

这里是验证器:

// __tests__/schemaValidation-test.js
import glob from 'glob'
import  validate  from 'graphql/validation'
import loader from 'graphql-tag/loader'
import schema from 'api/lib/app/graphql/schema'
import path from 'path'
import fs from 'fs'

const gqlDir = path.join(__dirname, '..')

const queryDir = path.join(gqlDir, 'queries', 'shared')
const pattern = `$queryDir/!(fragments)*.graphql`

const getGraphqlFiles = () => glob.sync(pattern)

describe('api schema', () => 
  const files = getGraphqlFiles()

  for(var file of files) 
    const buffer = fs.readFileSync(file)
    let document = (buffer || "").toString()

    try 
      document = eval(loader.call(
         cacheable: () => () ,
        document
      ))
     catch (e) 
      fail(`could not parse $file, $e`)
    


    it(`$file passes validation`, () => 
      const errors = validate(
        schema,
        document,
      )

      expect(errors).toEqual([])
    )
  
)

如何告诉加载器我在相对于片段不同的目录中?

【问题讨论】:

FWIW, graphql-tag 明确声明它不应该用于测试。您应该改用jest-transform-graphql,如here 所述。 值得一提的是上面的代码只会验证你的模式。如果您真的对识别重大更改感兴趣,您应该对架构进行快照,然后使用核心库中的 findBreakingChanges 实用程序。 是的,这就是我的直接目标。我会看看你推荐的图书馆。丹尼尔,我也在用变压器。只是不适用于这个例子,我想支持自动发现添加到 repo 的 *.graphql 文件 这个库不能满足我的需求,它看起来好像比较了 2 个模式。我只能访问 API 公开的单一模式。 另外,在这种情况下,我正在积极使用 graphql-tag 来支持片段。除非您知道另一种加载 graphql 扩展和相关片段的方法 【参考方案1】:

我想通了。关键是使用require 而不是fs.readFileSync

import glob from 'glob'
import  validate  from 'graphql/validation'
import schema from 'api/lib/app/graphql/schema'
import path from 'path'

const gqlDir = path.join(__dirname, '..')
const queryDir = path.join(gqlDir, 'queries', 'shared')
const pattern = `$queryDir/!(fragments)*.graphql`

const getGraphqlFiles = () => glob.sync(pattern)

describe('rent-js-api schema', () => 
  const files = getGraphqlFiles()
  files.forEach(file => 
    /* eslint-disable import/no-dynamic-require */
    const document = require(file)

    it(`$file passes validation`, () => 
      const errors = validate(
        schema,
        document,
      )

      expect(errors).toEqual([])
    )
  )
)

这里是 jest.config.json


  "setupFiles": [
    "<rootDir>/test/jest/shim.js",
    "<rootDir>/test/jest/setup.js"
  ],
  "moduleDirectories": ["node_modules", "src", "test/jest", "test"],
  "collectCoverage": false,
  "testMatch": ["**/*-test.js"],
  "collectCoverageFrom": [
    "**/src/**/*.js,ts,jsx,tsx",
    "!**/src/**/*-test.js",
    "!**/index.ts,js",
    "!**/src/**/const.ts,js",
    "!**/ui/theme/**",
    "!**/src/**/*.d.ts,tsx",
    "!**/node_modules/**",
    "!**/src/ui/*/themes/**"
  ],
  "coverageDirectory": "./coverage",
  "moduleNameMapper": 
    "\\.(css|scss)$": "<rootDir>/test/jest/noop-styles",
    "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/test/jest/noop-binary",
    "^.+\\.html$": "<rootDir>/test/jest/htmlLoader"
  ,
  "moduleFileExtensions": [
    "graphql",
    "js",
    "json",
    "ts",
    "tsx"
  ],
  "transform": 
    "^.+\\.jsx?$": "babel-jest",
    "^.+\\.tsx?$": "babel-jest",
    "^.+\\.graphql$": "jest-transform-graphql"
  ,
  "testPathIgnorePatterns": [
    "<rootDir>/node_modules/",
    "^.*__tests__/__helpers__.*"
  ],
  "snapshotSerializers": [
    "enzyme-to-json/serializer",
    "jest-serializer-html"
  ]

【讨论】:

以上是关于如何使用碎片化文档验证 graphql 模式的主要内容,如果未能解决你的问题,请参考以下文章

如何在没有循环依赖的情况下在 GraphQL 中拆分模式?

如何自定义 GraphQL 查询验证错误消息

GraphQL 的 GitHub API 身份验证:如果需要身份验证,我如何公开发布我的应用程序?

如何使用 Firebase Auth 作为 OIDC 向 Amplify GraphQL 发出经过身份验证的请求?

GraphQL 中的社交身份验证

如何正确声明不带参数的 GraphQL 查询。