{"id":13452037,"url":"https://github.com/EasyGraphQL/easygraphql-load-tester","last_synced_at":"2025-03-23T19:33:30.236Z","repository":{"id":47076080,"uuid":"157990686","full_name":"EasyGraphQL/easygraphql-load-tester","owner":"EasyGraphQL","description":"This package will create queries from your schema to use with your favorite load testing package.","archived":false,"fork":false,"pushed_at":"2021-09-14T15:18:06.000Z","size":1375,"stargazers_count":195,"open_issues_count":17,"forks_count":27,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-03-22T06:32:06.155Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/EasyGraphQL.png","metadata":{"files":{"readme":"README.MD","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-11-17T14:10:11.000Z","updated_at":"2025-01-07T13:51:42.000Z","dependencies_parsed_at":"2022-09-17T05:24:10.506Z","dependency_job_id":null,"html_url":"https://github.com/EasyGraphQL/easygraphql-load-tester","commit_stats":null,"previous_names":[],"tags_count":25,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EasyGraphQL%2Feasygraphql-load-tester","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EasyGraphQL%2Feasygraphql-load-tester/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EasyGraphQL%2Feasygraphql-load-tester/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EasyGraphQL%2Feasygraphql-load-tester/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/EasyGraphQL","download_url":"https://codeload.github.com/EasyGraphQL/easygraphql-load-tester/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244966507,"owners_count":20539796,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-07-31T07:01:10.881Z","updated_at":"2025-03-23T19:33:30.201Z","avatar_url":"https://github.com/EasyGraphQL.png","language":"TypeScript","funding_links":[],"categories":["TypeScript","JavaScript"],"sub_categories":[],"readme":"\u003ch1 align=\"center\"\u003e\n  \u003cimg src=\"https://raw.githubusercontent.com/EasyGraphQL/easygraphql-now/master/logo.png\" alt=\"easygraphql-load-tester \" width=\"350\"\u003e\n  \u003cbr\u003e\n    easygraphql-load-tester\n  \u003cbr\u003e\n  \u003cbr\u003e\n\u003c/h1\u003e\n\neasygraphql-load-tester is a node library created to make load\ntesting on GraphQL based on the schema; it'll create a bunch of queries, that\nare going to be the ones used to test your server.\n\n## Installation\n\nTo install the package on your project just run on the root of your project\n\n```shell\n$ npm install easygraphql-load-tester --saved-dev\n\n$ yarn add easygraphql-load-tester -D\n```\n\n[`easygraphql-load-tester`](https://github.com/EasyGraphQL/easygraphql-load-tester)\n\n## Supported packages\n\n1. Using `.artillery()` with a [artillery](https://artillery.io) setup.\n2. Using `.k6()` with a [k6](https://docs.k6.io/docs) setup.\n3. Using `.createQuery()` that'll create the queries, so you can use with your favorite load tester.\n\n## How to use it?\n\n- Import [`easygraphql-load-tester`](https://github.com/EasyGraphQL/easygraphql-load-tester) package.\n- Read the schema.\n- Initialize the tester, and pass the schema as the first argument.\n  - If there are multiples schemas pass an array with the schemas an argument.\n  - **Note**: In order to use multiples schema files, the queries and mutations must be extended. +\n- The second argument is the arguments on the queries, **only** if there are some of them.\n\n### One schema file\n\n```js\n'use strict'\n\nconst LoadTesting = require('easygraphql-load-tester')\nconst fs = require('fs')\nconst path = require('path')\n\nconst userSchema = fs.readFileSync(\n  path.join(__dirname, 'schema', 'user.gql'),\n  'utf8'\n)\n\nconst loadTester = new LoadTesting(userSchema)\n```\n\n### Multiples schemas files\n\n```js\n'use strict'\n\nconst LoadTesting = require('easygraphql-load-tester')\nconst fs = require('fs')\nconst path = require('path')\n\nconst userSchema = fs.readFileSync(\n  path.join(__dirname, 'schema', 'user.gql'),\n  'utf8'\n)\nconst familySchema = fs.readFileSync(\n  path.join(__dirname, 'schema', 'family.gql'),\n  'utf8'\n)\n\nconst loadTester = new LoadTesting([userSchema, familySchema])\n```\n\n### Using GraphQL.js\n\n```js\n'use strict'\n\nconst { GraphQLSchema, GraphQLObjectType, GraphQLString } = require('graphql')\nconst LoadTesting = require('easygraphql-load-tester')\n\nconst schema = new GraphQLSchema({\n  query: new GraphQLObjectType({\n    name: 'RootQueryType',\n    fields: {\n      hello: {\n        type: GraphQLString,\n        resolve() {\n          return 'world'\n        },\n      },\n    },\n  }),\n})\n\nconst loadTester = new LoadTesting(schema)\n```\n\n## Artillery\n\nTo use with [artillery](https://artillery.io), you must have it installed in your project,\nin case you don't have it just run:\n\n```shell\n$ npm install artillery --saved-dev\n```\n\n### index.js\n\nYou should configure your `index.js` file:\n\n```js\n'use strict'\n\nconst fs = require('fs')\nconst path = require('path')\nconst LoadTesting = require('../../lib')\n\nconst familySchema = fs.readFileSync(path.join(__dirname, 'schema.gql'), 'utf8')\n\nconst args = {\n  getFamilyInfoByIsLocal: {\n    isLocal: true,\n    test: ['a', 'b'],\n    age: 10,\n    name: 'test',\n  },\n  searchUser: {\n    name: 'demo',\n  },\n  createUser: {\n    name: 'demo',\n  },\n  createCity: {\n    input: {\n      name: 'demo',\n      country: 'Demo',\n    },\n  },\n}\n\nconst easyGraphQLLoadTester = new LoadTesting(familySchema, args)\n\nconst customQueries = [\n  `\n    query SEARCH_USER($name: String!) {\n      searchUser(name: $name) {\n        name\n      }\n    }\n  `,\n]\n\nconst testCases = easyGraphQLLoadTester.artillery({\n  customQueries,\n  onlyCustomQueries: true,\n  queryFile: true,\n  withMutations: true,\n})\n\nmodule.exports = {\n  testCases,\n}\n```\n\n### Artillery options\n\n```ts\ntype ArtilleryOptions = {\n  customQueries?: string[]\n  onlyCustomQueries?: boolean\n  selectedQueries?: string[]\n  queryFile?: boolean\n  queryFilePath?: string\n  withMutations?: boolean\n}\n```\n\n_This is optional, you can leave the second argument empty, if you don't want to pass any options_\n\n#### Custom queries\n\nYou can pass custom queries to test on your load test. To create them, create\nan array of strings (queries). You can use variables, and it's going to use the\nvariables defined on the arguments used to initialize `LoadTesting` or, you can\npass the value of the argument `searchUser(name: \"demo\") {...}`\n\n```js\nconst customQueries = [\n  `\n    query SEARCH_USER($name: String!) {\n      searchUser(name: $name) {\n        name\n      }\n    }\n  `,\n]\n```\n\n#### Only custom queries\n\nIf this is set to `true` it's going to use the custom queries passed.\n\n#### Selected queries\n\nYou can select a list of the queries you want to test, to do this, you must create an\narray of strings with the name of the queries to test; this is optional, if you don't\ncreate it, all the queries are going to be tested.\n\n```js\nconst selectedQueries = ['getFamilyInfo', 'searchUser']\n```\n\n#### Query file\n\nYou can select, if you want to save a `json` file with all the queries that where tested,\nto do it, on the options pass `queryFile: true`, if you don't pass anything it is not going\nto be saved.\n\n### Query file path\n\nYou can select the path that you want to use to save the query file, if it's not set\nit'll use by default `path.resolve()`\n\n#### Mutations\n\nYou can use [`easygraphql-load-tester`](https://github.com/EasyGraphQL/easygraphql-load-tester) to test\nyour mutations as well; to do it, on the options pass `withMutations: true`, if you don't pass anything it is only\ngoing to test the queries.\n_If you set `withMutations: true`, don't forget to add the input values on the args_\n\n### artillery.yml\n\nThe artillery file should have this minimum configuration, you can add yours in case it is needed:\n\n```yml\nconfig:\n  target: 'http://localhost:5000/'\n  phases:\n    - duration: 5\n      arrivalRate: 1\n  processor: './index.js'\nscenarios:\n  - name: 'GraphQL Query load test'\n    flow:\n      - function: 'testCases'\n      - loop:\n          - post:\n              url: '/'\n              json:\n                query: '{{ $loopElement.query }}'\n                variables: '{{ $loopElement.variables }}'\n          - log: '----------------------------------'\n          - log: 'Sent a request to the {{ $loopElement.operation }}: {{ $loopElement.name }}'\n          - log: 'And variables {{ $loopElement.variables }}'\n        over: cases\n```\n\n_In this case the server is running on http://localhost:5000/_\n\n### How to run it\n\nTo run your load test, add this script on your `package.json`:\n\n```json\n\"scripts\": {\n  \"easygraphql-load-tester\": \"artillery run artillery.yml\"\n}\n```\n\nand then run on the terminal\n\n```shell\n$ npm run easygraphql-load-tester\n```\n\n_In this case the artillery file is called artillery, but you can name yours with your favorite name and run `artillery run \u003cMY_FILE_NAME\u003e.yml`_\n\n### Result\n\nThe result is going to be something like this if you apply the basic configuration\n\n```shell\n All virtual users finished\n Summary report @ 15:03:05(-0500) 2018-11-17\n   Scenarios launched:  5\n   Scenarios completed: 5\n   Requests completed:  40\n   RPS sent: 8.95\n   Request latency:\n     min: 1.2\n     max: 13\n     median: 2\n     p95: 6\n     p99: 13\n   Scenario counts:\n     GraphQL Query load test: 5 (100%)\n   Codes:\n     200: 40\n```\n\n## k6\n\nTo use with [k6](https://docs.k6.io/docs/), you must have it installed on your computer,\nin case you don't have it, visit the [installation guide](https://docs.k6.io/docs/installation)\n\n### index.js\n\nYou should configure your `index.js` file:\n\n```js\n'use strict'\n\nconst fs = require('fs')\nconst path = require('path')\nconst LoadTesting = require('../../lib')\n\nconst familySchema = fs.readFileSync(path.join(__dirname, 'schema.gql'), 'utf8')\n\nconst args = {\n  getFamilyInfoByIsLocal: {\n    isLocal: true,\n    test: ['a', 'b'],\n    age: 10,\n    name: 'test',\n  },\n  searchUser: {\n    name: 'demo',\n  },\n}\n\nconst easyGraphQLLoadTester = new LoadTesting(familySchema, args)\n\nconst queries = [\n  `\n    query SEARCH_USER($name: String!) {\n      searchUser(name: $name) {\n        name\n      }\n    }\n  `,\n]\n\neasyGraphQLLoadTester.k6('k6.js', {\n  customQueries: queries,\n  selectedQueries: ['getFamilyInfo', 'searchUser'],\n  vus: 10,\n  duration: '10s',\n  queryFile: true,\n  out: ['json=my_test_result.json'],\n})\n```\n\n**The first argument is the name of the k6 configuration file**\n\n### K6 options\n\n```ts\ntype K6Options = {\n  customQueries?: string[]\n  onlyCustomQueries?: boolean\n  selectedQueries?: string[]\n  queryFile?: boolean\n  queryFilePath?: string\n  withMutations?: boolean\n  vus?: number\n  duration?: string\n  iterations?: number\n  out?: string[]\n}\n```\n\n_This is optional, you can leave the second argument empty, if you don't want to pass any options_\n\n#### Custom queries\n\nYou can pass custom queries to test on your load test. To create them, create\nan array of strings (queries). You can use variables, and it's going to use the\nvariables defined on the arguments used to initialize `LoadTesting` or, you can\npass the value of the argument `searchUser(name: \"demo\") {...}`\n\n```js\nconst customQueries = [\n  `\n    query SEARCH_USER($name: String!) {\n      searchUser(name: $name) {\n        name\n      }\n    }\n  `,\n]\n```\n\n#### Only custom queries\n\nIf this is set to `true` it's going to use the custom queries passed.\n\n#### Selected queries\n\nYou can select a list of the queries you want to test, to do this, you must create an\narray of strings with the name of the queries to test; this is optional, if you don't\ncreate it, all the queries are going to be tested.\n\n```js\nconst selectedQueries = ['getFamilyInfo', 'searchUser']\n```\n\n#### Query file\n\nYou can select, if you want to save a `json` file with all the queries that where tested,\nto do it, on the options pass `queryFile: true`, if you don't pass anything it is not going\nto be saved.\n\n#### Mutations\n\nYou can use [`easygraphql-load-tester`](https://github.com/EasyGraphQL/easygraphql-load-tester) to test\nyour mutations as well; to do it, on the options pass `withMutations: true`, if you don't pass anything it is only\ngoing to test the queries.\n_If you set `withMutations: true`, don't forget to add the input values on the args_\n\n#### Virtual users\n\nYou can select how many virtual users do you want for your tests, just pass to the options\n`vus: \u003cNUMBER_OF_VUS\u003e`.\n\n#### Duration\n\nYou can select the duration for your tests, just pass to the options\n`duration: '\u003cDURATION\u003es'`. It should be a string with units of the time e.g. `s`\n\n#### Iterations\n\nYou can select the number of iterations to run by passing\n`iterations: \u003cITERATIONS\u003e`. It should be an integer.\n\n#### Out\n\nYou can also make k6 output detailed statistics in JSON format by using the --out/-o option for k6 run.\n[More info](https://docs.k6.io/docs/results-output)\n\n### k6.js\n\nThe k6 file should have this minimum configuration, you can add yours in case it is needed:\n\n**Note: dont' change the name and the route of the queries `./easygraphql-load-tester-queries.json`**\n\n```js\nimport http from 'k6/http'\n\nconst queries = JSON.parse(open('./easygraphql-load-tester-queries.json'))\n\nexport default function() {\n  for (const query of queries) {\n    const url = 'http://localhost:5000/'\n    const payload = JSON.stringify({\n      query: query.query,\n      variables: query.variables,\n    })\n    const params = { headers: { 'Content-Type': 'application/json' } }\n    http.post(url, payload, params)\n  }\n}\n```\n\n_In this case the server is running on http://localhost:5000/_\n\n### How to run it\n\nTo run your load test, add this script on your `package.json`:\n\n```json\n\"scripts\": {\n  \"easygraphql-load-tester\": \"node index.js\"\n}\n```\n\nand then run on the terminal\n\n```shell\n$ npm run easygraphql-load-tester\n```\n\n## How to use it with your actual queries\n\n1. Install in your project [`merge-graphql-schemas`](https://github.com/Urigo/merge-graphql-schemas)\n2. Import all your queries:\n   ```js\n   const queries = fileLoader(path.join(__dirname, '..', '**/*.graphql'))\n   ```\n3. Pass them as `customQueries` in the options, with `onlyCustomQueries: true` as well.\n4. Set in the args the values to used on the variables of the queries/mutations.\n\n## Success cases\n\nIf you want to share your success case using [`easygraphql-load-tester`](https://github.com/EasyGraphQL/easygraphql-load-tester)\nfeel free to create a [PR](https://github.com/EasyGraphQL/easygraphql-load-tester/pulls) so the community\ncan learn from your story.\n\n## Importance of using dataloaders\n\nSome time ago I was working on a GraphQL project that includes activities and\neach activity can have some comments with the info of the user that created the comment.\nThe first thing that you might think is that it is a problem of query n + 1 , and yes; it is!\n\nI decided to implement dataloaders but for some reason, there was an error on the\nimplementation, so it wasn't caching the query and the result was a lot of\nrequest to the database. After finding that issue I implemented it on the right\nway reducing the queries to the database from 46 to 6.\n\n### Results without dataloaders\n\n```shell\nAll virtual users finished\nSummary report @ 10:07:55(-0500) 2018-11-23\n  Scenarios launched:  5\n  Scenarios completed: 5\n  Requests completed:  295\n  RPS sent: 36.88\n  Request latency:\n    min: 1.6\n    max: 470.9\n    median: 32.9\n    p95: 233.2\n    p99: 410.8\n  Scenario counts:\n    GraphQL Query load test: 5 (100%)\n  Codes:\n    200: 295\n```\n\n### Results with dataloaders\n\n```shell\nAll virtual users finished\nSummary report @ 10:09:09(-0500) 2018-11-23\n  Scenarios launched:  5\n  Scenarios completed: 5\n  Requests completed:  295\n  RPS sent: 65.85\n  Request latency:\n    min: 1.5\n    max: 71.9\n    median: 3.3\n    p95: 19.4\n    p99: 36.2\n  Scenario counts:\n    GraphQL Query load test: 5 (100%)\n  Codes:\n    200: 295\n```\n\n## Examples\n\nYou can check the [example](https://github.com/EasyGraphQL/easygraphql-load-tester/tree/master/examples)\n\n# License\n\n### The MIT License\n\nCopyright (c) 2018 EasyGraphQL\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FEasyGraphQL%2Feasygraphql-load-tester","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FEasyGraphQL%2Feasygraphql-load-tester","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FEasyGraphQL%2Feasygraphql-load-tester/lists"}