<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Katelyn Truong</title>
    <description>The latest articles on Forem by Katelyn Truong (@cupcakepanda89).</description>
    <link>https://forem.com/cupcakepanda89</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F443848%2F7a652e91-d065-42a6-822f-4430088c7160.jpeg</url>
      <title>Forem: Katelyn Truong</title>
      <link>https://forem.com/cupcakepanda89</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/cupcakepanda89"/>
    <language>en</language>
    <item>
      <title>GraphQL Schema Test with GraphQL Inspector</title>
      <dc:creator>Katelyn Truong</dc:creator>
      <pubDate>Thu, 30 Jul 2020 23:52:23 +0000</pubDate>
      <link>https://forem.com/beanworks/graphql-schema-inspector-test-32e7</link>
      <guid>https://forem.com/beanworks/graphql-schema-inspector-test-32e7</guid>
      <description>&lt;h3&gt;
  
  
  Background
&lt;/h3&gt;

&lt;p&gt;We were nearing the alpha release of &lt;strong&gt;one of our new modules&lt;/strong&gt; which includes the release of a &lt;strong&gt;new mobile application.&lt;/strong&gt; Our web app, new mobile app and our desktop app, all consume our graphQL API. &lt;br&gt;
To increase the reliability of our platform, we needed to formalize and implement a backwards compatibility and deprecation policy for our GraphQL API.&lt;br&gt;
The rules to add or delete from schema were&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Only add new fields. &lt;/li&gt;
&lt;li&gt;If you want to remove a field, deprecate it and remove it when it’s no longer in use. &lt;/li&gt;
&lt;li&gt;If you want to change an existing field, create a new field, deprecate the old field and remove it once it’s no longer in use.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;However, since the mobile app has a much larger footprint as users might be using the app with the older version with old graphQL schema, having a test for it seemed inevitable. Our existing e2e automation on mobile did not cover all graphQL endpoints, and it would have been too expensive and time consuming to cover all endpoints from a user interface perspective. Moreover, we wanted backward compatibility test to be a test that runs before we run e2e tests to detect breaking changes earlier in the cycle.&lt;/p&gt;

&lt;p&gt;Since we needed something light weight and graphQL compatible, we decided to use &lt;a href="https://graphql-inspector.com/" rel="noopener noreferrer"&gt;GraphQL Inspector Tool&lt;/a&gt; to &lt;strong&gt;ensure backward compatibility&lt;/strong&gt; and prevent schema breaking changes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tech Stack
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Bitbucket (Git)&lt;/li&gt;
&lt;li&gt;Codeship Pro for CI/CD workflow&lt;/li&gt;
&lt;li&gt;Docker&lt;/li&gt;
&lt;li&gt;GraphQL&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Code Structure
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F40iho56itks2rj4ygbor.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F40iho56itks2rj4ygbor.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Why GraphQL Inspector Tool?
&lt;/h3&gt;

&lt;p&gt;We decide to use GraphQL Inspector Tool for graphQL backward capability test because of following reasons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GraphQL compatibility &lt;/li&gt;
&lt;li&gt;Ease of implementation with custom rules &lt;/li&gt;
&lt;li&gt;Easy CLI command for CI integration &lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Steps to Implement
&lt;/h3&gt;

&lt;h5&gt;
  
  
  Step1: Create a dockerfile for &lt;a href="https://graphql-inspector.com/" rel="noopener noreferrer"&gt;GraphQL Inspector&lt;/a&gt;
&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;Dockerfile template can be found here at &lt;a href="https://hub.docker.com/r/kamilkisiela/graphql-inspector" rel="noopener noreferrer"&gt;graphQL inspector docker hub&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Dockerfile can be named as &lt;code&gt;Dockerfile.graphqlInspector&lt;/code&gt; in &lt;code&gt;./codeship&lt;/code&gt; folder
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; node:10-slim&lt;/span&gt;

&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; LOG_LEVEL "debug"&lt;/span&gt;
&lt;span class="k"&gt;ARG&lt;/span&gt;&lt;span class="s"&gt; PRIVATE_SSH_KEY&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;apt update 
&lt;span class="k"&gt;RUN &lt;/span&gt;apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; ssh
&lt;span class="k"&gt;RUN &lt;/span&gt;yarn global add @graphql-inspector/cli@2.1.0 graphql
&lt;span class="k"&gt;RUN &lt;/span&gt;apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; git-all

&lt;span class="c"&gt;# Copy the decrypt ssh private key for Bitbucket Readonly User to allow codeship access to &lt;/span&gt;
&lt;span class="c"&gt;# Our repository from codeship container  &lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; /root/.ssh
&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$PRIVATE_SSH_KEY&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; /root/.ssh/id_rsa
&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;chmod &lt;/span&gt;600 /root/.ssh/id_rsa
&lt;span class="k"&gt;RUN &lt;/span&gt;ssh-keyscan &lt;span class="nt"&gt;-H&lt;/span&gt; bitbucket.org &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; /root/.ssh/known_hosts

&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; /app
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h5&gt;
  
  
  Step2: Create an entrypoint file
&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;This file will be triggered after docker image is built &lt;/li&gt;
&lt;li&gt;Name file &lt;code&gt;entrypoint-graphql-inspector.sh&lt;/code&gt;  in &lt;code&gt;./codeship&lt;/code&gt; folder

&lt;ul&gt;
&lt;li&gt;To add git remote for our repository

&lt;ul&gt;
&lt;li&gt;Note: it uses remote name as &lt;code&gt;api&lt;/code&gt; because &lt;code&gt;origin&lt;/code&gt; already taken and it doesn't work in codeship&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;To fetch the master branch which will use for &lt;code&gt;graphql inspector command&lt;/code&gt; in codeship
&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
git remote add api git@bitbucket.org:&amp;lt;owner_name&amp;gt;/&amp;lt;repo_name&amp;gt;.git
git fetch api master
&lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$@&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h5&gt;
  
  
  Step3: Create graphQL inspector test service
&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;graphql-inspector-test&lt;/code&gt; service will be placed in &lt;code&gt;./codeship-services.yml&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Build from &lt;code&gt;Dockerfile.graphqlInspector&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Include &lt;em&gt;entrypoint&lt;/em&gt; link with &lt;code&gt;entrypoint-graphql-inspector.sh&lt;/code&gt; to trigger the command line after finishing pulling and building the docker image from &lt;em&gt;dockerfile&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;For &lt;code&gt;volumes&lt;/code&gt;, it can be different depending on your code structure or same as created above in &lt;em&gt;dockerfile&lt;/em&gt;.

&lt;ul&gt;
&lt;li&gt;How to find which volume to mount&lt;/li&gt;
&lt;li&gt;Install jet if you have not  (for locally running commands for &lt;em&gt;codeship&lt;/em&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cd &amp;lt;repo&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;jet run SERVICE_NAME pwd&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Example: &lt;code&gt;jet run graphql-inspector-test pwd&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;With &lt;code&gt;pwd&lt;/code&gt;, it will show the path of the volume where it should be mounted
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;graphql-inspector-test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./&lt;/span&gt;
      &lt;span class="na"&gt;dockerfile&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./codeship/Dockerfile.graphqlInspector&lt;/span&gt;
      &lt;span class="na"&gt;encrypted_args_file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;path_to_encrypted_git_ssh_key&amp;gt;&lt;/span&gt;
    &lt;span class="na"&gt;encrypted_env_file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;path_to_encrypted_git_ssh_key&amp;gt;&lt;/span&gt;
    &lt;span class="na"&gt;entrypoint&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sh"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;./codeship/entrypoint-graphql-inspector.sh"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;cached&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;.:/app&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h5&gt;
  
  
  Step4: Create graphql-inspector-test step
&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;GraphQL Schema Inspector Test&lt;/em&gt; test step under &lt;em&gt;Jest Tests&lt;/em&gt; in &lt;code&gt;./codeship-steps.yml&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;graphql-inspector-test&lt;/code&gt; service&lt;/li&gt;
&lt;li&gt;To trigger command &lt;code&gt;graphql-inspector diff git:api/master:./src/generated/graphql/schema.graphql ./src/generated/graphql/schema.graphql --rule ./src/generated/graphql/custom-rule.js&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;serial&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Continuous Integration&lt;/span&gt;
  &lt;span class="na"&gt;encrypted_dockercfg_path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dockercfg.encrypted&lt;/span&gt;
  &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Tests&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;parallel&lt;/span&gt;
    &lt;span class="na"&gt;exclude&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;^(production)&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Jest Tests&lt;/span&gt;
      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;serial&lt;/span&gt;
      &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Jest Tests for E2E Tests&lt;/span&gt;
        &lt;span class="na"&gt;service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;e2e-runner&lt;/span&gt;
        &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;yarn test&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ESLint for E2E Tests&lt;/span&gt;
        &lt;span class="na"&gt;service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;e2e-runner&lt;/span&gt;
        &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;yarn run lint&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Graph QL Test&lt;/span&gt;
        &lt;span class="na"&gt;service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;graphql-test&lt;/span&gt;
        &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;yarn run graphql-test&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Graph QL Schema Inspector Test&lt;/span&gt;
        &lt;span class="na"&gt;service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;graphql-inspector-test&lt;/span&gt;
        &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;graphql-inspector diff&lt;/span&gt;
                 &lt;span class="s"&gt;git:api/master:./src/generated/graphql/schema.graphql&lt;/span&gt;             
                 &lt;span class="s"&gt;./src/generated/graphql/schema.graphql --rule&lt;/span&gt; 
                 &lt;span class="s"&gt;./src/generated/graphql/custom-rule.js&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy to Dev and Production&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h5&gt;
  
  
  Step5: How to create custom rules for graphQL inspector test
&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;For details, you can see &lt;a href="https://graphql-inspector.com/docs/essentials/diff#custom-rules" rel="noopener noreferrer"&gt;graphql inspector custom rules&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;We use &lt;em&gt;custom-rules&lt;/em&gt; to skip certain attributes that we don’t want the test to run 

&lt;ul&gt;
&lt;li&gt;Example: the field may not be available to mobile apps yet and still under development, so there may be many changes to the field.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Create file name &lt;code&gt;custom-rules.js&lt;/code&gt; in the folder where you have your &lt;code&gt;schema.graphql&lt;/code&gt;
&lt;/li&gt;

&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// custom-rules.js&lt;/span&gt;
&lt;span class="cm"&gt;/**
 * @summary exceptionSet is an array of schema attributes that can be skipped during graphql schema diff test
 * for breaking changes. 
 * !important: by adding to exceptionSet, there is a risk of graphql schema test will skip these attributes
 * example: new Set(['Form.user]);
 */&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;exceptionSet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;([]);&lt;/span&gt;

&lt;span class="cm"&gt;/**
 * @summary changes is an object array of all breaking changes [{error1},{error2}]
 * Each error object contains these key value pairs as follow 
 * critical: { level: 'BREAKING', reason: "some reason"}
 * type: 'FIELD_TYPE_CHANGED' or 'FIELD_REMOVED' or 'ENUM_VALUE_REMOVED', etc... 
 * message: "Field 'XYZ' was removed from interface 'ABC'"
 * path: graphql schema attribute, eg: 'Comment.description' 
 */&lt;/span&gt;
&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;changes&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;included&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;excluded&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
    &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;change&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;changes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;exceptionSet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;change&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;excluded&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;change&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nx"&gt;included&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;change&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;excluded&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;warnColor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s1"&gt;x1b[33m&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;The following changes have been excluded from breaking changes test:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;change&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;excluded&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// print something sensible - should show that the field was excluded&lt;/span&gt;
            &lt;span class="c1"&gt;// and what potential problem we're ignoring ;-)&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`!!! &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;change&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;change&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;warnColor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;included&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  How to execute test locally
&lt;/h3&gt;

&lt;h5&gt;
  
  
  Prerequisite
&lt;/h5&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--global&lt;/span&gt; @graphql-inspector/cli graphql
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h5&gt;
  
  
  Steps
&lt;/h5&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; &amp;lt;repo_folder&amp;gt; 
graphql-inspector diff git:origin/master:./src/generated/graphql/schema.graphql ./src/generated/graphql/schema.graphql &lt;span class="nt"&gt;--rule&lt;/span&gt; ./src/generated/graphql/custom-rule.js

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fmt5t0d9giz9eldcygkfn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fmt5t0d9giz9eldcygkfn.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;We were successfully able to add &lt;em&gt;graphQL backward capabilities test&lt;/em&gt; that is easy to maintain, and is platform agnostic by using &lt;a href="https://graphql-inspector.com/" rel="noopener noreferrer"&gt;GraphQL Inspector Tool&lt;/a&gt;. We are able to gain a better understanding of how API should be handled for projects, where the same API is used across multiple platforms (i.e. web, desktop and mobile).&lt;/p&gt;

</description>
      <category>graphql</category>
      <category>testing</category>
      <category>apitesting</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
