如何使用jest

时间:2018-05-31 06:02:10

标签: graphql jestjs graphql-js graphql-tag

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

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

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

要使用模拟的解析器和数据创建GraphQL架构,我使用graphql-tools中的makeExecutableSchemaaddMockFunctionsToSchema

要从开玩笑测试中运行查询,我的理解是我需要使用graphql-js中的graphql()函数。

此功能需要将查询作为字符串,因此我尝试了两种不同的方式,但它们都没有工作:

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

3 个答案:

答案 0 :(得分:0)

您可以使用此:

import { print } from 'graphql/language/printer'

import query from './query.gql'

...

print(query)

答案 1 :(得分:0)

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

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

答案 2 :(得分:0)

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

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

据我所知,最好的选择是在将片段发送到服务器之前将片段标记到查询源。您需要明确找到以#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;
};