首页 > 解决方案 > 如何使用碎片化文档验证 graphql 模式

问题描述

我认为在单元测试级别支持模式验证会很酷,这样我们就可以在升级 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

我尝试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([])
    })
  }
})

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

标签: node.jsgraphqljestjs

解决方案


我想通了。关键是使用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"
  ]
}

推荐阅读