【问题标题】:How to test GraphQL queries with fragments using jest如何使用 jest 测试带有片段的 GraphQL 查询
【发布时间】:2018-11-10 01:45:11
【问题描述】:

问题:我想测试一个位于 .graphql 文件中的 GraphQL 查询,如下所示:

#import '../../fragments/Widget.graphql'

query WidgetFragment($id: ID) {
    readWidgetFragment(id: $id) {
        ...Widget
    }
}

要使用模拟解析器和数据创建 GraphQL 架构,我使用来自 graphql-toolsmakeExecutableSchemaaddMockFunctionsToSchema

要从一个笑话测试中运行查询,我的理解是我需要使用来自graphql-jsgraphql() 函数。

这个函数需要将查询作为字符串,所以我尝试了两种不同的方法,但都没有奏效:

  • .graphql 文件解析为普通文本文件,给我原始字符串(在我的笑话配置中使用jest-raw-loader)。 当我运行查询时,这给了我:Failed: Errors in query: Unknown fragment "Widget".
  • 使用jest-transform-graphql.graphql 文件解析为query 对象。我相信这应该是正确的方法,因为它应该正确解析任何导入的片段。但是,要执行查询,我需要将 query.loc.source.body 传递给 graphql,这会导致与选项 1 相同的错误消息。

【问题讨论】:

    标签: graphql jestjs graphql-js graphql-tag


    【解决方案1】:

    是的,这真是个泡菜。即使导入正常工作(>= v2.1.0 for jest-transform-graphql,它们也会被添加到 query.definitions 对象中,这在使用 document.loc.source.body 作为查询参数调用 graphql 时完全回避。

    在服务器端,graphql (function graphqlImpl) 将使用 parse(source) 重构 document 对象 - 但它对导入的片段定义的了解为零...

    据我所知,最好的办法是在将片段发送到服务器之前将其标记到查询源。您需要明确查找以 #import 开头的所有行,并将这些行替换为要导入的 graphql 文件的实际文本内容。

    以下是我使用的功能。 (未测试递归片段)

    // Async wrapper around dynamic `import` function
    import { importQuery } from "./queries";
    
    const importAndReplace = async (fileToImport, sourceDocument, line) => {
      const doc = await importQuery(fileToImport);
      const targetDocument = (await sourceDocument).replace(line, doc.loc.source.body);
      return targetDocument;
    };
    
    // Inspired by `graphql-tag/loader` 
    // Uses promises because of async function `importQuery` used
    export default async graphqlOperation => {
      const { body } = graphqlOperation.loc.source;
      const lines = body.split(/\r\n|\r|\n/);
      const bodyWithInlineImports = await lines.reduce(
        async (accumulator, line) => {
          await accumulator;
          const lineSplit = line.slice(1).split(" ");
    
          return line[0] === "#" && lineSplit[0] === "import"
            ? importAndReplace(lineSplit[1].replace(/"/g, ""), accumulator, line)
            : Promise.resolve(accumulator);
        },
        Promise.resolve(body)
      );
      return bodyWithInlineImports;
    };

    【讨论】:

      【解决方案2】:

      使用初始方法将其解析为原始文本,除了:

      1. 使用带有路径参数的递归函数(假设您可以有嵌套片段)
      2. 它使用regex 将所有导入预先提取到一个数组中(也许使用更好的模式:))
      3. 将文件的其余部分附加到字符串变量中
      4. 然后循环导入,解析 #imports 并将它们传递给自身并将结果附加到字符串变量
      5. 最后将结果返回给你将它传递给graphql()的主函数

      【讨论】:

        【解决方案3】:

        你可以用这个:

        import { print } from 'graphql/language/printer'
        
        import query from './query.gql'
        
        ...
        
        print(query)
        

        【讨论】:

          猜你喜欢
          • 2016-05-04
          • 2016-10-28
          • 2017-02-24
          • 2020-07-19
          • 2021-08-19
          • 2021-05-12
          • 2019-06-20
          • 2018-11-03
          • 2021-03-24
          相关资源
          最近更新 更多