├── .github
├── dependabot.yml
└── workflows
│ ├── ci.yaml
│ ├── maven-deploy.yaml
│ └── release.yaml
├── .gitignore
├── CHANGELOG.md
├── LICENSE
├── README.md
├── docs
└── MatchStrategy.md
├── e2e
├── .gitignore
├── Makefile
├── env
│ └── default
│ │ ├── default.properties
│ │ └── java.properties
├── fixtures
│ ├── alias-match
│ │ ├── request.json
│ │ └── setup.json
│ ├── alias-not-match
│ │ ├── request.json
│ │ └── setup.json
│ ├── argument-match
│ │ ├── request.json
│ │ └── setup.json
│ ├── argument-not-match
│ │ ├── request.json
│ │ └── setup.json
│ ├── exact-match
│ │ ├── request.json
│ │ └── setup.json
│ ├── fragment-match
│ │ ├── request.json
│ │ └── setup.json
│ ├── fragment-name-match
│ │ ├── request.json
│ │ └── setup.json
│ ├── fragment-set-not-match
│ │ ├── request.json
│ │ └── setup.json
│ ├── multiple-fragments-match
│ │ ├── request.json
│ │ └── setup.json
│ ├── multiple-fragments-not-match
│ │ ├── request.json
│ │ └── setup.json
│ ├── not-match
│ │ ├── request.json
│ │ └── setup.json
│ ├── order-match
│ │ ├── request.json
│ │ └── setup.json
│ ├── query-match
│ │ ├── request.json
│ │ └── setup-query.graphql
│ ├── query-variables-match
│ │ ├── request.json
│ │ ├── setup-query.graphql
│ │ └── setup-variables.json
│ ├── variables-array-order-not-match
│ │ ├── request.json
│ │ └── setup.json
│ ├── variables-complex-match
│ │ ├── request.json
│ │ └── setup.json
│ ├── variables-match
│ │ ├── request.json
│ │ └── setup.json
│ ├── variables-not-match
│ │ ├── request.json
│ │ └── setup.json
│ └── with-other
│ │ ├── request.json
│ │ └── setup.json
├── manifest.json
├── pom.xml
├── specs
│ ├── match.spec
│ ├── variables-match.spec
│ └── with-other-mappings.spec
└── src
│ └── test
│ ├── kotlin
│ ├── Configuration.kt
│ ├── Datastore.kt
│ ├── ExecutionHooks.kt
│ └── Steps.kt
│ └── resources
│ └── config.properties
├── examples
├── testcontainers-java
│ ├── .gitignore
│ ├── README.md
│ ├── pom.xml
│ └── src
│ │ └── test
│ │ └── java
│ │ └── TestSample.java
└── testcontainers-kotlin
│ ├── .gitignore
│ ├── README.md
│ ├── pom.xml
│ └── src
│ └── test
│ └── kotlin
│ └── TestSample.kt
└── wiremock-graphql-extension
├── .dockerignore
├── Dockerfile
├── pom.xml
└── src
├── main
├── kotlin
│ └── io
│ │ └── github
│ │ └── nilwurtz
│ │ ├── EqualToGraphqlQueryPattern.kt
│ │ └── GraphqlBodyMatcher.kt
└── resources
│ └── META-INF
│ └── services
│ └── com.github.tomakehurst.wiremock.extension.Extension
└── test
├── kotlin
└── io
│ └── github
│ └── nilwurtz
│ ├── EqualToGraphqlQueryPatternTest.kt
│ ├── GraphqlBodyMatcherTest.kt
│ └── integration
│ └── ContainerTest.kt
└── resources
└── mappings
├── all.json
├── operationName.json
├── query.json
└── variables.json
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: "maven"
4 | directory: "/e2e"
5 | schedule:
6 | interval: "daily"
7 | open-pull-requests-limit: 10
8 | reviewers:
9 | - "nilwurtz"
10 | auto-merge:
11 | enabled: true
12 | strategy: "merge"
13 |
14 | - package-ecosystem: "maven"
15 | directory: "/wiremock-graphql-extension"
16 | schedule:
17 | interval: "daily"
18 | open-pull-requests-limit: 10
19 | reviewers:
20 | - "nilwurtz"
21 | auto-merge:
22 | enabled: true
23 | strategy: "merge"
--------------------------------------------------------------------------------
/.github/workflows/ci.yaml:
--------------------------------------------------------------------------------
1 | name: CI
2 |
3 | on:
4 | push:
5 | branches:
6 | - main
7 | paths:
8 | - 'e2e/**'
9 | - 'examples/**'
10 | - 'wiremock-graphql-extension/**'
11 | workflow_dispatch:
12 |
13 | jobs:
14 | test:
15 | runs-on: ubuntu-latest
16 |
17 | steps:
18 | - name: Check out repository
19 | uses: actions/checkout@v4
20 |
21 | - name: Set up Java 17
22 | uses: actions/setup-java@v4
23 | with:
24 | java-version: '17'
25 | distribution: 'corretto'
26 |
27 | - uses: getgauge/setup-gauge@master
28 | with:
29 | gauge-version: '1.6.9'
30 | gauge-plugins: java, html-report
31 |
32 | - name: Run unit test and install
33 | run: make install
34 | working-directory: e2e
35 |
36 | - name: Run docker for e2e
37 | run: make docker
38 | working-directory: e2e
39 |
40 | - name: Run e2e
41 | run: make clean test_compile run TAGS='!unimplemented'
42 | working-directory: e2e
43 |
44 | - name: Run remote e2e
45 | run: |-
46 | sed -i 's/baseUrl=http:\/\/localhost:8080/baseUrl=http:\/\/localhost:8888/' src/test/resources/config.properties
47 | make run TAGS='!unimplemented,remote'
48 | working-directory: e2e
49 |
50 | check-example-validity:
51 | runs-on: ubuntu-latest
52 |
53 | steps:
54 | - name: Check out repository
55 | uses: actions/checkout@v4
56 |
57 | - name: Set up Java 17
58 | uses: actions/setup-java@v4
59 | with:
60 | java-version: '17'
61 | distribution: 'corretto'
62 |
63 | - name: Install to local repository
64 | run: mvn install -DskipTests=true -Dmaven.javadoc.skip=true -B -V
65 | working-directory: wiremock-graphql-extension
66 |
67 | - name: Check example validity kotlin
68 | run: mvn test
69 | working-directory: examples/testcontainers-kotlin
70 |
71 | - name: Check example validity java
72 | run: mvn test
73 | working-directory: examples/testcontainers-java
74 |
--------------------------------------------------------------------------------
/.github/workflows/maven-deploy.yaml:
--------------------------------------------------------------------------------
1 | name: Publish package
2 |
3 | on:
4 | workflow_dispatch:
5 |
6 | jobs:
7 | publish:
8 | runs-on: ubuntu-latest
9 | steps:
10 | - uses: actions/checkout@v4
11 |
12 | - name: Set up Maven Central Repository
13 | uses: actions/setup-java@v4
14 | with:
15 | java-version: '17'
16 | distribution: 'corretto'
17 | server-id: ossrh
18 | server-username: MAVEN_USERNAME
19 | server-password: MAVEN_USER_PASSWORD
20 | gpg-passphrase: MAVEN_GPG_PASSPHRASE
21 | gpg-private-key: ${{ secrets.MAVEN_GPG_PRIVATE_KEY }}
22 |
23 | - name: Publish package
24 | working-directory: wiremock-graphql-extension
25 | run: mvn --batch-mode --no-transfer-progress deploy -Dgpg.skip=false
26 | env:
27 | MAVEN_USERNAME: ${{ secrets.MAVEN_USERNAME }}
28 | MAVEN_USER_PASSWORD: ${{ secrets.MAVEN_USER_PASSWORD }}
29 | MAVEN_GPG_PASSPHRASE: ${{ secrets.MAVEN_GPG_PASSPHRASE }}
--------------------------------------------------------------------------------
/.github/workflows/release.yaml:
--------------------------------------------------------------------------------
1 | name: Build and Release
2 |
3 | on:
4 | workflow_dispatch:
5 |
6 | permissions:
7 | contents: write
8 |
9 | jobs:
10 | build_and_release:
11 | runs-on: ubuntu-latest
12 |
13 | steps:
14 | - name: Checkout repository
15 | uses: actions/checkout@v4
16 |
17 | - name: Set up Java 17
18 | uses: actions/setup-java@v4
19 | with:
20 | java-version: '17'
21 | distribution: 'corretto'
22 |
23 | - name: Get Target version
24 | working-directory: wiremock-graphql-extension
25 | id: version
26 | run: |-
27 | VERSION=$(mvn help:evaluate -Dexpression=project.version -B | grep -v '\[INFO\]')
28 | echo $VERSION
29 | echo "version=$VERSION" >> $GITHUB_OUTPUT
30 |
31 | - name: Build and package JAR
32 | run: mvn -f wiremock-graphql-extension clean package
33 |
34 | - name: Create GitHub Release
35 | uses: softprops/action-gh-release@v1
36 | with:
37 | files: wiremock-graphql-extension/target/wiremock-graphql-extension-*.jar
38 | tag_name: v${{ steps.version.outputs.version }}
39 | name: Release v${{ steps.version.outputs.version }}
40 | env:
41 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
42 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Gauge - metadata dir
2 | .gauge
3 |
4 | # Gauge - log files dir
5 | logs
6 |
7 | # Gauge - reports generated by reporting plugins
8 | reports
9 |
10 | # Gauge - java class output directory
11 | gauge_bin
12 |
13 | # Gauge - java class target dir
14 | target
15 |
16 | target/
17 | !.mvn/wrapper/maven-wrapper.jar
18 | !**/src/main/**/target/
19 | !**/src/test/**/target/
20 |
21 | ### IntelliJ IDEA ###
22 | .idea/
23 | *.iws
24 | *.iml
25 | *.ipr
26 |
27 | ### Eclipse ###
28 | .apt_generated
29 | .classpath
30 | .factorypath
31 | .project
32 | .settings
33 | .springBeans
34 | .sts4-cache
35 |
36 | ### NetBeans ###
37 | /nbproject/private/
38 | /nbbuild/
39 | /dist/
40 | /nbdist/
41 | /.nb-gradle/
42 | build/
43 | !**/src/main/**/build/
44 | !**/src/test/**/build/
45 |
46 | ### VS Code ###
47 | .vscode/
48 |
49 | ### Mac OS ###
50 | .DS_Store
51 |
52 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 |
3 | All notable changes to this project will be documented in this file.
4 |
5 | The format is based on [Keep a Changelog](http://keepachangelog.com/)
6 | and this project adheres to [Semantic Versioning](http://semver.org/).
7 |
8 | ## [Unreleased]
9 |
10 | ### Added
11 |
12 | ### Changed
13 |
14 | ## [0.9.0] - 2024-10-08
15 |
16 | ### Changed
17 |
18 | - Update dependencies ([#24](https://github.com/wiremock/wiremock-graphql-extension/pull/24) from @bgalek)
19 | - Update wiremock 3.0.3 -> 3.9.0
20 | - Update graphql-java 21.0 -> 22.3
21 | - Update mockk 1.13.8 -> 1.13.12
22 | - Update testcontainers 1.19.3 -> 1.20.2
23 | - Update junit 5.10.1 -> 5.11.1
24 | - Update mockk 1.13.8 -> 1.13.12
25 |
26 | ## [0.8.2] - 2024-01-04
27 |
28 | ### Added
29 |
30 | - Added `operationName` parameter ([#18](https://github.com/wiremock/wiremock-graphql-extension/pull/18) from @kyle-winkelman)
31 | - Added `GraphqlBodyMatcher.parameters` method which can use create `Parameters` easily ([#18](https://github.com/wiremock/wiremock-graphql-extension/pull/18) from @kyle-winkelman)
32 |
33 | ### Changed
34 |
35 | - Remove `org.json:json` dependency in favor of reusing `com.github.tomakehurst.wiremock.common.Json` ([#18](https://github.com/wiremock/wiremock-graphql-extension/pull/18) from @kyle-winkelman)
36 | - Deprecate `withRequestJson` and `withRequest` in favor of `parameters` ([#18](https://github.com/wiremock/wiremock-graphql-extension/pull/18) from @kyle-winkelman)
37 |
38 | ## [0.8.1] - 2023-12-12
39 |
40 | ### Changed
41 |
42 | - Added `@JvmStatic` annotation to `GraphqlBodyMatcher.Companion.withRequest` method to allow Java clients to use the method without `Companion`. ([#16](https://github.com/wiremock/wiremock-graphql-extension/pull/16) from @kyle-winkelman)
43 |
44 | ## [0.8.0] - 2023-12-08
45 |
46 | ### Changed
47 |
48 | - Implemented `graphql-java`'s `AstSorter` and `AstComparator` for GraphQL query normalization. This integration significantly aligns the supported GraphQL features of our extension with those of `graphql-java`. ([#14](https://github.com/wiremock/wiremock-graphql-extension/pull/14) from @kyle-winkelman)
49 |
50 | ## [0.7.1] - 2023-11-25
51 |
52 | ### Changed
53 |
54 | - Update dev dependencies (kotlin, mockk, junit, testcontainers)
55 |
56 | ### Fixed
57 |
58 | - Improved handling of newline characters in JSON strings. Newline characters are now removed to prevent parsing errors (`JSONException: Unterminated string`) when processing JSON data. This change ensures that JSON strings with embedded newlines are handled correctly by the `String.toJSONObject()` method. ([#11](https://github.com/wiremock/wiremock-graphql-extension/issues/11))
59 |
60 | ## [0.7.0] - 2023-09-27
61 |
62 | ### Changed
63 |
64 | - Throws `InvalidQueryException` and `InvalidJsonException` when `withRequest` is called.
65 | - When `match` method is called, it will not throw any exception if the request is invalid.
66 |
67 | ## [0.6.2] - 2023-09-08
68 |
69 | ### Added
70 |
71 | - Added `withRequest` method which can used easily when using remote wiremock server.
72 |
73 | ## [0.6.1] - 2023-08-31
74 |
75 | ### Changed
76 |
77 | - Update target jvmVersion 1.8 -> 11
78 | - Update graphql-java 20.2 -> 21.0
79 | - Update json 20230227 -> 20230618
80 | - Update dev dependencies (kotlin, mockk, junit)
81 |
82 | ## [0.6.0] (deprecated) - 2023-08-31
83 |
84 | ### Changed
85 |
86 | - Update wiremock 2.27.2 -> 3.0.0!
87 | - `withRequestQueryAndVariables` method has been changed to deprecate.
88 |
89 | ## [0.5.0] - 2023-08-11
90 |
91 | ### Added
92 |
93 | - Added `GraphqlBodyMatcher.extensionName` which can used easily when using remote wiremock server.
94 |
95 | ### Changed
96 |
97 | - Change parameter key `expectedQuery` to `expectedJson` for remote wiremock server.
98 |
99 | ## [0.4.0] - 2023-05-25
100 |
101 | ### Added
102 |
103 | - Support Remote Wiremock Server.
104 |
105 | ## [0.3.0] - 2023-04-26
106 |
107 | ### Added
108 |
109 | - Support Graphql Variables.
110 |
111 | ### Changed
112 |
113 | - `withRequestQuery` method has been changed to `withRequestQueryAndVariables` and now takes `expectedVariables` as argument. `expectedVariables` is Nullable.
114 | - Update junit 5.8.1 -> 5.9.2
115 | - Update mockk-jvm 1.13.4 -> 1.13.5
116 |
117 | ## [0.2.1] - 2023-04-21
118 |
119 | ### Added
120 |
121 | - Support fragment normalization.
122 |
123 | ## [0.2.0] - 2023-04-21
124 |
125 | ### Changed
126 |
127 | - Use `withRequestJson or Query` instead of constructor.
128 |
129 | ## [0.1.x]
130 |
131 | Prerelease Version.
132 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 nilwurtz
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Graphql Wiremock Extension - Graphql Body Matcher
2 |
3 | ⚠️ **IMPORTANT**: Starting from version 0.6, this extension requires WireMock 3.x. WireMock 2.x is no longer supported from this version onwards.
4 |
5 | _An extension for GraphQL testing with Wiremock_
6 |
7 | GraphqlBodyMatcher is an extension for [WireMock](https://wiremock.org/) that allows for semantical verification of GraphQL requests.
8 |
9 | GraphqlBodyMatcher は[WireMock](https://wiremock.org/)の拡張で、GraphQL のリクエストが意味的に一致しているかを検証します。
10 |
11 | ## Overview 📖
12 |
13 | - In addition to handling whitespaces, the extension sorts and normalizes queries. The GraphQL parsing and normalizing is handled by `graphql-java`.
14 | - Beyond just queries, it also compares variables. For the comparison of JSON variables, [EqualToJsonPattern](https://github.com/wiremock/wiremock/blob/3.3.1/src/main/java/com/github/tomakehurst/wiremock/matching/EqualToJsonPattern.java) is used. It's important to note that the order of arrays must match.
15 |
16 | For a comprehensive understanding of our matching logic and details on our match strategy, please refer to our [MatchStrategy documentation](./docs/MatchStrategy.md).
17 |
18 | - この拡張機能は、空白の取り扱いに加えて、クエリをソートし正規化します。GraphQL のパースおよび正規化には`graphql-java`を使用しています。
19 | - クエリだけでなく、変数も比較されます。変数の JSON の比較には`org.json.JSONObject.similar`を使用しますが、配列の順番も一致している必要があります。
20 |
21 | 詳しいマッチングロジックなど関しては、[MatchStrategy のドキュメント](./docs/MatchStrategy.md)を参照してください。
22 |
23 | ## Usage 🛠️
24 |
25 | ### For Gradle:
26 |
27 | ```groovy
28 | repositories {
29 | mavenCentral()
30 | }
31 |
32 | dependencies {
33 | testImplementation 'io.github.nilwurtz:wiremock-graphql-extension:0.9.0'
34 | }
35 | ```
36 |
37 | ### For Maven:
38 |
39 | ```xml
40 |
41 | io.github.nilwurtz
42 | wiremock-graphql-extension
43 | 0.9.0
44 | test
45 |
46 | ```
47 |
48 | ## Code Examples 💡
49 |
50 | Here are some code examples to get started.
51 |
52 | ```java Java
53 | import com.github.tomakehurst.wiremock.client.WireMock;
54 | import io.github.nilwurtz.GraphqlBodyMatcher;
55 |
56 | import java.util.Map;
57 |
58 | var expectedQuery = """
59 | query HeroInfo($id: Int) {
60 | hero(id: $id) {
61 | name
62 | }
63 | }
64 | """;
65 | var expectedVariables = Map.of("id", 1);
66 |
67 | WireMock.stubFor(WireMock.post(WireMock.urlEqualTo("/graphql"))
68 | .andMatching(GraphqlBodyMatcher.extensionName, GraphqlBodyMatcher.parameters(expectedQuery, expectedVariables))
69 | .willReturn(WireMock.okJson("""
70 | {
71 | "data": {
72 | "hero": {
73 | "name": "example"
74 | }
75 | }
76 | }""")));
77 | ```
78 |
79 | ```kotlin Kotlin
80 | import com.github.tomakehurst.wiremock.client.WireMock
81 | import io.github.nilwurtz.GraphqlBodyMatcher
82 |
83 | val expectedQuery = """
84 | query HeroInfo(${'$'}id: Int) {
85 | hero(id: ${'$'}id) {
86 | name
87 | }
88 | }
89 | """.trimIndent()
90 | val expectedVariables = mapOf("id" to 1)
91 |
92 | WireMock.stubFor(
93 | WireMock.post(WireMock.urlEqualTo("/graphql"))
94 | .andMatching(GraphqlBodyMatcher.extensionName, GraphqlBodyMatcher.parameters(expectedQuery, expectedVariables))
95 | .willReturn(
96 | WireMock.okJson("""
97 | {
98 | "data": {
99 | "hero": {
100 | "name": "example"
101 | }
102 | }
103 | }
104 | """.trimIndent()
105 | )
106 | )
107 | )
108 | ```
109 |
110 | As we head towards a 1.0 release, we are focusing on supporting both the WireMock standalone and the WireMock Java API
111 | with the same paradigm. This is done through the use of `WireMock.requestMatching()` or `MappingBuilder#andMatching()`.
112 | To that end, the `withRequestQueryAndVariables` method has been deprecated from version 0.6.0 onwards and
113 | `withRequestJson` and `withRequest` methods have been deprecated from version 0.9.0 onwards.
114 |
115 | ## Running with a Remote Wiremock Server 🌍
116 |
117 | If you are using Wiremock on a remote server such as Docker, please see the configurations below:
118 |
119 | Please download `wiremock-graphql-extension-x.y.z-jar-with-dependencies.jar` from the Release section.
120 |
121 | ### Server Configuration
122 |
123 | #### When running with `docker run`:
124 |
125 | ```
126 | docker run -it --rm \
127 | -p 8080:8080 \
128 | --name wiremock \
129 | -v /path/to/wiremock-graphql-extension-0.9.0-jar-with-dependencies.jar:/var/wiremock/extensions/wiremock-graphql-extension-0.9.0-jar-with-dependencies.jar \
130 | wiremock/wiremock \
131 | --extensions io.github.nilwurtz.GraphqlBodyMatcher
132 | ```
133 |
134 | #### When building with `docker build`:
135 |
136 | ```dockerfile
137 | FROM wiremock/wiremock:latest
138 | COPY ./wiremock-graphql-extension-0.9.0-jar-with-dependencies.jar /var/wiremock/extensions/wiremock-graphql-extension-0.9.0-jar-with-dependencies.jar
139 | ```
140 |
141 | ### Client-side (Test) Configuration
142 |
143 | NOTE: When using a Remote Wiremock Server, you're requested to manage everything within a single JSON format.
144 |
145 | ```java Java
146 | import com.github.tomakehurst.wiremock.client.WireMock;
147 | import io.github.nilwurtz.GraphqlBodyMatcher;
148 |
149 | import static com.github.tomakehurst.wiremock.client.WireMock.*;
150 |
151 | public registerGraphQLWiremock(String query, String response) {
152 | WireMock(8080).register(
153 | post(urlPathEqualTo(endPoint))
154 | .andMatching(GraphqlBodyMatcher.extensionName, GraphqlBodyMatcher.parameters(query))
155 | .willReturn(okJson(response)));
156 | }
157 | ```
158 |
159 | ```kotlin Kotlin
160 | import com.github.tomakehurst.wiremock.client.WireMock
161 | import com.github.tomakehurst.wiremock.client.WireMock.*
162 | import io.github.nilwurtz.GraphqlBodyMatcher
163 |
164 | fun registerGraphQLWiremock(query: String, response: String) {
165 | WireMock(8080).register(
166 | post(urlPathEqualTo(endPoint))
167 | .andMatching(GraphqlBodyMatcher.extensionName, GraphqlBodyMatcher.parameters(query))
168 | .willReturn(okJson(response)))
169 | }
170 | ```
171 |
172 | ## License 📜
173 |
174 | This project is licensed under the terms of the MIT License.
175 |
176 | ## Contributing 🤝
177 |
178 | Contributions are welcome! Feel free to open an issue or submit a pull request if you have any improvements or suggestions.
179 |
--------------------------------------------------------------------------------
/docs/MatchStrategy.md:
--------------------------------------------------------------------------------
1 | # Match Strategy
2 |
3 | ## queries
4 |
5 | The two queries below are considered matching:
6 |
7 | ```graphql
8 | {
9 | hero {
10 | name
11 | friends {
12 | name
13 | age
14 | }
15 | }
16 | }
17 | ```
18 | ```graphql
19 | {
20 | hero {
21 | friends {
22 | age
23 | name
24 | }
25 | name
26 | }
27 | }
28 | ```
29 | But, these aren't:
30 | ```graphql
31 | {
32 | hero {
33 | name
34 | friends {
35 | name
36 | age
37 | }
38 | }
39 | }
40 | ```
41 | ```graphql
42 | {
43 | hero {
44 | name
45 | friends {
46 | name
47 | }
48 | }
49 | }
50 | ```
51 |
52 | ## Variables
53 |
54 | Similar rules apply for variable matching based on `org.json.JsonObject.similar`.
55 |
56 | ```json
57 | {
58 | "id": 1,
59 | "name": "John Doe"
60 | }
61 | ```
62 |
63 | ```json
64 | {
65 | "name": "John Doe",
66 | "id": 1
67 | }
68 | ```
69 |
70 | However, the following two variables do not match because the order of the arrays is different.
71 |
72 | ```json
73 | {
74 | "ids": [1, 2, 3]
75 | }
76 | ```
77 | ```json
78 | {
79 | "ids": [3, 2, 1]
80 | }
81 | ```
--------------------------------------------------------------------------------
/e2e/.gitignore:
--------------------------------------------------------------------------------
1 | # Gauge - metadata dir
2 | .gauge
3 |
4 | # Gauge - log files dir
5 | logs
6 |
7 | # Gauge - reports generated by reporting plugins
8 | reports
9 |
10 | # Gauge - java class output directory
11 | gauge_bin
12 |
13 | # Gauge - java class target dir
14 | target
15 |
--------------------------------------------------------------------------------
/e2e/Makefile:
--------------------------------------------------------------------------------
1 | .PHONY: all install test_compile run
2 |
3 | all: install clean test_compile run
4 |
5 | install:
6 | cd ../wiremock-graphql-extension && mvn install -Dmaven.wagon.http.progress=false
7 |
8 | clean:
9 | mvn clean
10 |
11 | test_compile:
12 | mvn test-compile -Dmaven.wagon.http.progress=false
13 |
14 | run:
15 | mvn gauge:execute -Dtags="$(TAGS)" -Dmaven.wagon.http.progress=false
16 |
17 | docker: docker/build docker/run
18 |
19 | docker/stop:
20 | docker stop $$(docker ps -q --filter ancestor=wiremock-graphql-extension:latest)
21 |
22 | docker/build:
23 | cd ../wiremock-graphql-extension && docker build -t wiremock-graphql-extension:latest .
24 |
25 | docker/run:
26 | docker run -p 8888:8080 -d wiremock-graphql-extension:latest
27 |
--------------------------------------------------------------------------------
/e2e/env/default/default.properties:
--------------------------------------------------------------------------------
1 | # default.properties
2 | # properties set here will be available to the test execution as environment variables
3 |
4 | # sample_key = sample_value
5 |
6 | # The path to the gauge reports directory. Should be either relative to the project directory or an absolute path
7 | gauge_reports_dir = reports
8 |
9 | # Set as false if gauge reports should not be overwritten on each execution. A new time-stamped directory will be created on each execution.
10 | overwrite_reports = true
11 |
12 | # Set to false to disable screenshots on failure in reports.
13 | screenshot_on_failure = true
14 |
15 | # The path to the gauge logs directory. Should be either relative to the project directory or an absolute path
16 | logs_directory = logs
17 |
18 | # Set to true to use multithreading for parallel execution
19 | enable_multithreading = false
20 |
21 | # Possible values for this property are 'suite', 'spec' or 'scenario'.
22 | # 'scenario' clears the objects after the execution of each scenario, new objects are created for next execution.
23 | gauge_clear_state_level = scenario
24 |
25 | # The path the gauge specifications directory. Takes a comma separated list of specification files/directories.
26 | gauge_specs_dir = specs
27 |
28 | # The default delimiter used read csv files.
29 | csv_delimiter = ,
30 |
31 | # Allows steps to be written in multiline
32 | allow_multiline_step = false
--------------------------------------------------------------------------------
/e2e/env/default/java.properties:
--------------------------------------------------------------------------------
1 |
2 | # Specify an alternate Java home if you want to use a custom version
3 | gauge_java_home =
4 |
5 | # IntelliJ and Eclipse out directory will be usually autodetected
6 | # Use the below property if you need to override the build path
7 | gauge_custom_build_path =
8 |
9 | # specify the directory where additional libs are kept
10 | # you can specify multiple directory names separated with a comma (,)
11 | gauge_additional_libs = libs/*
12 |
13 | # JVM arguments passed to java while launching. Enter multiple values separated by comma (,) eg. Xmx1024m, Xms128m
14 | gauge_jvm_args =
15 |
16 | # specify the directory containing java files to be compiled
17 | # you can specify multiple directory names separated with a comma (,)
18 | gauge_custom_compile_dir =
19 |
20 | # specify the level at which the objects should be cleared
21 | # Possible values are suite, spec and scenario. Default value is scenario.
22 | gauge_clear_state_level = scenario
23 |
--------------------------------------------------------------------------------
/e2e/fixtures/alias-match/request.json:
--------------------------------------------------------------------------------
1 | {
2 | "query": "{ mainHero: hero { name } }"
3 | }
--------------------------------------------------------------------------------
/e2e/fixtures/alias-match/setup.json:
--------------------------------------------------------------------------------
1 | {
2 | "query": "{ mainHero: hero { name } }"
3 | }
--------------------------------------------------------------------------------
/e2e/fixtures/alias-not-match/request.json:
--------------------------------------------------------------------------------
1 | {
2 | "query": "{ main_hero: hero { name } }"
3 | }
--------------------------------------------------------------------------------
/e2e/fixtures/alias-not-match/setup.json:
--------------------------------------------------------------------------------
1 | {
2 | "query": "{ mainHero: hero { name } }"
3 | }
--------------------------------------------------------------------------------
/e2e/fixtures/argument-match/request.json:
--------------------------------------------------------------------------------
1 | {
2 | "query": "{ hero(episode: NEWHOPE) { name } }"
3 | }
--------------------------------------------------------------------------------
/e2e/fixtures/argument-match/setup.json:
--------------------------------------------------------------------------------
1 | {
2 | "query": "{ hero(episode: NEWHOPE) { name } }"
3 | }
--------------------------------------------------------------------------------
/e2e/fixtures/argument-not-match/request.json:
--------------------------------------------------------------------------------
1 | {
2 | "query": "{ hero(episode: EMPIRE) { name } }"
3 | }
--------------------------------------------------------------------------------
/e2e/fixtures/argument-not-match/setup.json:
--------------------------------------------------------------------------------
1 | {
2 | "query": "{ hero(episode: NEWHOPE) { name } }"
3 | }
--------------------------------------------------------------------------------
/e2e/fixtures/exact-match/request.json:
--------------------------------------------------------------------------------
1 | {
2 | "query": "query { hero { name }}"
3 | }
--------------------------------------------------------------------------------
/e2e/fixtures/exact-match/setup.json:
--------------------------------------------------------------------------------
1 | {
2 | "query": "query { hero { name }}"
3 | }
--------------------------------------------------------------------------------
/e2e/fixtures/fragment-match/request.json:
--------------------------------------------------------------------------------
1 | {
2 | "query": "fragment heroDetails on Hero { name } { hero { ...heroDetails } }"
3 | }
--------------------------------------------------------------------------------
/e2e/fixtures/fragment-match/setup.json:
--------------------------------------------------------------------------------
1 | {
2 | "query": "fragment heroDetails on Hero { name } { hero { ...heroDetails } }"
3 | }
--------------------------------------------------------------------------------
/e2e/fixtures/fragment-name-match/request.json:
--------------------------------------------------------------------------------
1 | {
2 | "query": "fragment heroDetails on Hero { name } { hero { ...heroDetails } }"
3 | }
--------------------------------------------------------------------------------
/e2e/fixtures/fragment-name-match/setup.json:
--------------------------------------------------------------------------------
1 | {
2 | "query": "fragment differentHeroDetails on Hero { name } { hero { ...heroDetails } }"
3 | }
--------------------------------------------------------------------------------
/e2e/fixtures/fragment-set-not-match/request.json:
--------------------------------------------------------------------------------
1 | {
2 | "query": "fragment heroDetails on Hero { name age } { hero { ...heroDetails } }"
3 | }
--------------------------------------------------------------------------------
/e2e/fixtures/fragment-set-not-match/setup.json:
--------------------------------------------------------------------------------
1 | {
2 | "query": "fragment heroDetails on Hero { name } { hero { ...heroDetails } }"
3 | }
--------------------------------------------------------------------------------
/e2e/fixtures/multiple-fragments-match/request.json:
--------------------------------------------------------------------------------
1 | {
2 | "query": "fragment heroInfo on Hero { name } fragment sidekickInfo on Sidekick { name age } { hero { ...heroInfo }, sidekick { ...sidekickInfo } }"
3 | }
--------------------------------------------------------------------------------
/e2e/fixtures/multiple-fragments-match/setup.json:
--------------------------------------------------------------------------------
1 | {
2 | "query": "fragment heroDetails on Hero { name } fragment sidekickDetails on Sidekick { name age } { hero { ...heroDetails }, sidekick { ...sidekickDetails } }"
3 | }
--------------------------------------------------------------------------------
/e2e/fixtures/multiple-fragments-not-match/request.json:
--------------------------------------------------------------------------------
1 | {
2 | "query": "fragment heroInfo on Hero { name } fragment sidekickInfo on Sidekick { name age } { hero { ...heroInfo }, sidekick { ...sidekickInfo } }"
3 | }
--------------------------------------------------------------------------------
/e2e/fixtures/multiple-fragments-not-match/setup.json:
--------------------------------------------------------------------------------
1 | {
2 | "query": "fragment heroDetails on Hero { age } fragment sidekickDetails on Sidekick { name age } { hero { ...heroDetails }, sidekick { ...sidekickDetails } }"
3 | }
--------------------------------------------------------------------------------
/e2e/fixtures/not-match/request.json:
--------------------------------------------------------------------------------
1 | {
2 | "query": "query { hero { namea }}"
3 | }
4 |
--------------------------------------------------------------------------------
/e2e/fixtures/not-match/setup.json:
--------------------------------------------------------------------------------
1 | {
2 | "query": "query { hero { name }}"
3 | }
--------------------------------------------------------------------------------
/e2e/fixtures/order-match/request.json:
--------------------------------------------------------------------------------
1 | {
2 | "query": "query { hero { name id }}"
3 | }
4 |
--------------------------------------------------------------------------------
/e2e/fixtures/order-match/setup.json:
--------------------------------------------------------------------------------
1 | {
2 | "query": "query { hero { id name }}"
3 | }
--------------------------------------------------------------------------------
/e2e/fixtures/query-match/request.json:
--------------------------------------------------------------------------------
1 | {
2 | "query": "fragment heroInfo on Hero { name } fragment sidekickInfo on Sidekick { name age } { hero { ...heroInfo }, sidekick { ...sidekickInfo } }"
3 | }
--------------------------------------------------------------------------------
/e2e/fixtures/query-match/setup-query.graphql:
--------------------------------------------------------------------------------
1 | fragment heroDetails on Hero { name } fragment sidekickDetails on Sidekick { name age } { hero { ...heroDetails }, sidekick { ...sidekickDetails } }
--------------------------------------------------------------------------------
/e2e/fixtures/query-variables-match/request.json:
--------------------------------------------------------------------------------
1 | {
2 | "query": "{ hero(id: 1) { name, friends { name } } }",
3 | "variables": {
4 | "id": 1
5 | }
6 | }
--------------------------------------------------------------------------------
/e2e/fixtures/query-variables-match/setup-query.graphql:
--------------------------------------------------------------------------------
1 | { hero(id: 1) { name, friends { name } } }
--------------------------------------------------------------------------------
/e2e/fixtures/query-variables-match/setup-variables.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": 1
3 | }
--------------------------------------------------------------------------------
/e2e/fixtures/variables-array-order-not-match/request.json:
--------------------------------------------------------------------------------
1 | {
2 | "query": "query GetCharacters($ids: [ID!]) { characters(ids: $ids) { name age } }",
3 | "variables": {
4 | "ids": [1, 2, 3]
5 | }
6 | }
--------------------------------------------------------------------------------
/e2e/fixtures/variables-array-order-not-match/setup.json:
--------------------------------------------------------------------------------
1 | {
2 | "query": "query GetCharacters($ids: [ID!]) { characters(ids: $ids) { name age } }",
3 | "variables": {
4 | "ids": [3, 1, 2]
5 | }
6 | }
--------------------------------------------------------------------------------
/e2e/fixtures/variables-complex-match/request.json:
--------------------------------------------------------------------------------
1 | {
2 | "query": "query GetCharacters($ids: [ID!], $info: CharacterInfo) { characters(ids: $ids, info: $info) { name age } }",
3 | "variables": {
4 | "ids": [1, 2, 3],
5 | "info": {
6 | "showOnlyActive": true,
7 | "minAge": 18
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/e2e/fixtures/variables-complex-match/setup.json:
--------------------------------------------------------------------------------
1 | {
2 | "query": "query GetCharacters($ids: [ID!], $info: CharacterInfo) { characters(ids: $ids, info: $info) { name age } }",
3 | "variables": {
4 | "info": {
5 | "minAge": 18,
6 | "showOnlyActive": true
7 | },
8 | "ids": [1, 2, 3]
9 | }
10 | }
--------------------------------------------------------------------------------
/e2e/fixtures/variables-match/request.json:
--------------------------------------------------------------------------------
1 | {
2 | "query": "query GetHero($episode: Episode) { hero(episode: $episode) { age name } }",
3 | "variables": {
4 | "episode": "JEDI"
5 | }
6 | }
--------------------------------------------------------------------------------
/e2e/fixtures/variables-match/setup.json:
--------------------------------------------------------------------------------
1 | {
2 | "query": "query GetHero($episode: Episode) { hero(episode: $episode) { age name } }",
3 | "variables": {
4 | "episode": "JEDI"
5 | }
6 | }
--------------------------------------------------------------------------------
/e2e/fixtures/variables-not-match/request.json:
--------------------------------------------------------------------------------
1 | {
2 | "query": "query GetHero($episode: Episode) { hero(episode: $episode) { name age } }",
3 | "variables": {
4 | "episode": "JEDI"
5 | }
6 | }
--------------------------------------------------------------------------------
/e2e/fixtures/variables-not-match/setup.json:
--------------------------------------------------------------------------------
1 | {
2 | "query": "query GetHero($episode: Episode) { hero(episode: $episode) { name age } }",
3 | "variables": {
4 | "episode": "EMPIRE"
5 | }
6 | }
--------------------------------------------------------------------------------
/e2e/fixtures/with-other/request.json:
--------------------------------------------------------------------------------
1 | {
2 | "query": "query GetHero($episode: Episode) { hero(episode: $episode) { name age } }",
3 | "variables": {
4 | "episode": "EMPIRE"
5 | }
6 | }
--------------------------------------------------------------------------------
/e2e/fixtures/with-other/setup.json:
--------------------------------------------------------------------------------
1 | {
2 | "query": "query GetHero($episode: Episode) { hero(episode: $episode) { name age } }",
3 | "variables": {
4 | "episode": "EMPIRE"
5 | }
6 | }
--------------------------------------------------------------------------------
/e2e/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "Language": "java",
3 | "Plugins": [
4 | "html-report"
5 | ]
6 | }
--------------------------------------------------------------------------------
/e2e/pom.xml:
--------------------------------------------------------------------------------
1 |
4 | 4.0.0
5 |
6 | io.github.nilwurtz
7 | e2e
8 | 1.0-SNAPSHOT
9 |
10 |
11 | true
12 | 11
13 | 1.9.10
14 | ${java.version}
15 | 0.11.1
16 | 1.6.3
17 | 3.0.3
18 | UTF-8
19 |
20 |
21 |
22 |
23 |
24 | wiremock-graphql-extension
25 | io.github.nilwurtz
26 | 0.9.0
27 |
28 |
29 | com.thoughtworks.gauge
30 | gauge-java
31 | ${gauge.java.version}
32 | test
33 |
34 |
35 | org.jetbrains.kotlin
36 | kotlin-stdlib
37 | ${kotlin.version}
38 |
39 |
40 | org.wiremock
41 | wiremock
42 | ${wiremock.version}
43 | test
44 |
45 |
46 |
47 |
48 | src/test/kotlin
49 |
50 |
51 | src/test/resources
52 |
53 |
54 |
55 |
56 | com.thoughtworks.gauge.maven
57 | gauge-maven-plugin
58 | ${gauge.maven.version}
59 |
60 |
61 | test
62 |
63 | specs
64 |
65 |
66 | execute
67 |
68 |
69 |
70 |
71 |
72 | org.jetbrains.kotlin
73 | kotlin-maven-plugin
74 | ${kotlin.version}
75 |
76 |
77 | -Xjsr305=strict
78 |
79 | ${kotlin.compiler.jvmTarget}
80 |
81 |
82 |
83 | compile
84 | compile
85 |
86 | compile
87 |
88 |
89 |
90 | test-compile
91 | test-compile
92 |
93 | test-compile
94 |
95 |
96 |
97 | src/test/kotlin
98 |
99 |
100 |
101 |
102 |
103 |
104 | org.apache.maven.plugins
105 | maven-compiler-plugin
106 |
107 | 11
108 | 11
109 |
110 |
111 |
112 |
113 |
114 |
--------------------------------------------------------------------------------
/e2e/specs/match.spec:
--------------------------------------------------------------------------------
1 | # Comparing Graphql Request Queries
2 |
3 | ## When JSON perfectly matches, it should match
4 | tags: remote
5 | * Register a stub to return 200 upon receiving json
6 | * Send a POST request to URL "/graphql" with body
7 | * The response status code should be "200"
8 |
9 | ## When JSON does not perfectly match, it should not match
10 | tags: remote
11 | * Register a stub to return 200 upon receiving json
12 | * Send a POST request to URL "/graphql" with body
13 | * The response status code should be "404"
14 |
15 | ## When JSON has different order, it should match
16 | tags: remote
17 | * Register a stub to return 200 upon receiving json
18 | * Send a POST request to URL "/graphql" with body
19 | * The response status code should be "200"
20 |
21 | ## When JSON uses aliases, it should match
22 | tags: remote
23 | * Register a stub to return 200 upon receiving json
24 | * Send a POST request to URL "/graphql" with body
25 | * The response status code should be "200"
26 |
27 | ## When JSON uses different aliases, it should not match
28 | tags: remote
29 | * Register a stub to return 200 upon receiving json
30 | * Send a POST request to URL "/graphql" with body
31 | * The response status code should be "404"
32 |
33 | ## When JSON uses the same fragments, it should match
34 | tags: remote
35 | * Register a stub to return 200 upon receiving json
36 | * Send a POST request to URL "/graphql" with body
37 | * The response status code should be "200"
38 |
39 | ## When JSON uses different fragment names for the same set, it should match
40 | tags: remote
41 | * Register a stub to return 200 upon receiving json
42 | * Send a POST request to URL "/graphql" with body
43 | * The response status code should be "200"
44 |
45 | ## When JSON uses the same fragment names for different sets, it should not match
46 | tags: remote
47 | * Register a stub to return 200 upon receiving json
48 | * Send a POST request to URL "/graphql" with body
49 | * The response status code should be "404"
50 |
51 | ## When the query contains multiple fragments, it should match
52 | tags: remote
53 | * Register a stub to return 200 upon receiving json
54 | * Send a POST request to URL "/graphql" with body
55 | * The response status code should be "200"
56 |
57 | ## When the query contains different sets with multiple fragments, it should not match
58 | tags: remote
59 | * Register a stub to return 200 upon receiving json
60 | * Send a POST request to URL "/graphql" with body
61 | * The response status code should be "404"
62 |
63 | ## When JSON has the same arguments, it should match
64 | tags: remote
65 | * Register a stub to return 200 upon receiving json
66 | * Send a POST request to URL "/graphql" with body
67 | * The response status code should be "200"
68 |
69 | ## When JSON has different arguments, it should not match
70 | tags: remote
71 | * Register a stub to return 200 upon receiving json
72 | * Send a POST request to URL "/graphql" with body
73 | * The response status code should be "404"
74 |
75 | ## Specifying the query should match
76 | * Register a stub to return 200 upon receiving the query
77 | * Send a POST request to URL "/graphql" with body
78 | * The response status code should be "200"
79 |
--------------------------------------------------------------------------------
/e2e/specs/variables-match.spec:
--------------------------------------------------------------------------------
1 | # Comparing Graphql Request queries and variables
2 |
3 | ## When the variables match exactly, it matches
4 | tags: remote
5 | * Register a stub to return 200 upon receiving json
6 | * Send a POST request to URL "/graphql" with body
7 | * The response status code should be "200"
8 |
9 | ## When the variables do not match exactly, it does not match
10 | tags: remote
11 | * Register a stub to return 200 upon receiving json
12 | * Send a POST request to URL "/graphql" with body
13 | * The response status code should be "404"
14 |
15 | ## When the variable properties order differs but the structure matches, it matches
16 | tags: remote
17 | * Register a stub to return 200 upon receiving json
18 | * Send a POST request to URL "/graphql" with body
19 | * The response status code should be "200"
20 |
21 | ## When the order of elements in the variable array differs, it does not match
22 | tags: remote
23 | * Register a stub to return 200 upon receiving json
24 | * Send a POST request to URL "/graphql" with body
25 | * The response status code should be "404"
26 |
27 | ## When the query and variables match, it matches
28 | * Register a stub to return 200 upon receiving the query and variables
29 | * Send a POST request to URL "/graphql" with body
30 | * The response status code should be "200"
31 |
--------------------------------------------------------------------------------
/e2e/specs/with-other-mappings.spec:
--------------------------------------------------------------------------------
1 | # With other mappings
2 |
3 | ## When using a mapping with this extension and normal mapping, graphql request should work
4 | tags: remote
5 | * Register a stub to return 200 upon receiving json
6 | * Register a normal stub to return 200 upon receiving json "{\"foo\": \"bar\"}"
7 | * Send a POST request to URL "/graphql" with body
8 | * The response status code should be "200"
9 |
10 | ## When using a mapping with this extension and normal mapping, normal request should work
11 | tags: remote
12 | * Register a stub to return 200 upon receiving json
13 | * Register a normal stub to return 200 upon receiving json "{\"foo\": \"bar\"}"
14 | * Send a POST request to URL "/graphql" with body "{\"foo\": \"bar\"}"
15 | * The response status code should be "200"
16 |
17 | ## When using a mapping with this extension and normal mapping (change order), normal request should work
18 | tags: remote
19 | * Register a normal stub to return 200 upon receiving json "{\"foo\": \"bar\"}"
20 | * Register a stub to return 200 upon receiving json
21 | * Send a POST request to URL "/graphql" with body "{\"foo\": \"bar\"}"
22 | * The response status code should be "200"
23 |
--------------------------------------------------------------------------------
/e2e/src/test/kotlin/Configuration.kt:
--------------------------------------------------------------------------------
1 | import java.util.*
2 |
3 | object Configuration {
4 | var baseUrl: String
5 |
6 | init {
7 | Properties().apply {
8 | load(Configuration::class.java.classLoader.getResourceAsStream("config.properties"))
9 | }
10 | .let {
11 | baseUrl = it.getProperty("baseUrl")
12 | }
13 | }
14 |
15 | }
--------------------------------------------------------------------------------
/e2e/src/test/kotlin/Datastore.kt:
--------------------------------------------------------------------------------
1 | import com.github.tomakehurst.wiremock.WireMockServer
2 | import com.github.tomakehurst.wiremock.client.WireMock
3 | import com.thoughtworks.gauge.datastore.SuiteDataStore
4 |
5 | object Datastore {
6 | fun localServer(): WireMockServer? {
7 | return SuiteDataStore.get("localServer") as WireMockServer?
8 | }
9 |
10 | fun localServer(client: WireMockServer) {
11 | SuiteDataStore.put("localServer", client)
12 | }
13 |
14 | fun client(): WireMock? {
15 | return SuiteDataStore.get("client") as WireMock?
16 | }
17 |
18 | fun client(client: WireMock) {
19 | SuiteDataStore.put("client", client)
20 | }
21 |
22 | fun statusCode(): Int? {
23 | return SuiteDataStore.get("statusCode") as Int?
24 | }
25 |
26 | fun statusCode(statusCode: Int) {
27 | SuiteDataStore.put("statusCode", statusCode)
28 | }
29 | }
--------------------------------------------------------------------------------
/e2e/src/test/kotlin/ExecutionHooks.kt:
--------------------------------------------------------------------------------
1 | import com.github.tomakehurst.wiremock.WireMockServer
2 | import com.github.tomakehurst.wiremock.client.WireMock
3 | import com.github.tomakehurst.wiremock.common.ConsoleNotifier
4 | import com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig
5 | import com.thoughtworks.gauge.AfterSuite
6 | import com.thoughtworks.gauge.BeforeScenario
7 | import com.thoughtworks.gauge.BeforeSuite
8 | import io.github.nilwurtz.GraphqlBodyMatcher
9 |
10 | class ExecutionHooks {
11 |
12 | @BeforeSuite()
13 | fun setupSuite() {
14 | // for remote
15 | WireMock(8888).let { Datastore.client(it) }
16 |
17 | // for local
18 | WireMockServer(
19 | wireMockConfig()
20 | .port(8080)
21 | .extensions(GraphqlBodyMatcher::class.java)
22 | .notifier(ConsoleNotifier(true))
23 | )
24 | .let {
25 | Datastore.localServer(it);
26 | it.start()
27 | }
28 | }
29 |
30 | @AfterSuite()
31 | fun tearDownSuite() {
32 | Datastore.localServer()?.shutdown()
33 | }
34 |
35 | @BeforeScenario()
36 | fun setupScenario() {
37 | Datastore.client()?.let {
38 | it.resetMappings()
39 | it.resetRequests()
40 | }
41 | Datastore.localServer()?.let {
42 | it.resetMappings()
43 | it.resetRequests()
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/e2e/src/test/kotlin/Steps.kt:
--------------------------------------------------------------------------------
1 | import com.github.tomakehurst.wiremock.client.WireMock.*
2 | import com.thoughtworks.gauge.Step
3 | import io.github.nilwurtz.GraphqlBodyMatcher
4 | import java.net.URI
5 | import java.net.http.HttpClient
6 | import java.net.http.HttpRequest
7 | import java.net.http.HttpResponse
8 |
9 | class Steps {
10 | @Step("Register a stub to return 200 upon receiving json ")
11 | fun setupGraphqlJsonStub(json: String) {
12 | // for remote
13 | Datastore.client()?.register(
14 | post(urlEqualTo("/graphql"))
15 | .andMatching(GraphqlBodyMatcher.extensionName, GraphqlBodyMatcher.withRequest(json)).willReturn(ok())
16 | )
17 | // for local
18 | Datastore.localServer()
19 | ?.stubFor(
20 | post(urlEqualTo("/graphql"))
21 | .andMatching(GraphqlBodyMatcher.extensionName, GraphqlBodyMatcher.withRequest(json))
22 | .willReturn(ok())
23 | )
24 | }
25 |
26 | @Step("Register a normal stub to return 200 upon receiving json ")
27 | fun setupJsonPostStub(json: String) {
28 | Datastore.client()?.register(
29 | post(urlEqualTo("/graphql"))
30 | .withRequestBody(equalToJson(json)).willReturn(ok())
31 | )
32 | Datastore.localServer()
33 | ?.stubFor(
34 | post(urlEqualTo("/graphql"))
35 | .withRequestBody(equalToJson(json))
36 | .willReturn(ok())
37 | )
38 | }
39 |
40 | @Step("Register a stub to return 200 upon receiving the query")
41 | fun setupGraphqlQueryStub(query: String) {
42 | Datastore.localServer()
43 | ?.stubFor(
44 | post(urlEqualTo("/graphql"))
45 | .andMatching(GraphqlBodyMatcher.withRequestQueryAndVariables(query)).willReturn(ok())
46 | )
47 | }
48 |
49 | @Step("Register a stub to return 200 upon receiving the query and variables")
50 | fun setupGraphqlQueryAndVariables(query: String, variables: String) {
51 | Datastore.localServer()
52 | ?.stubFor(
53 | post(urlEqualTo("/graphql"))
54 | .andMatching(GraphqlBodyMatcher.withRequestQueryAndVariables(query, variables)).willReturn(ok())
55 | )
56 | }
57 |
58 | @Step("Send a POST request to URL with body ")
59 | fun requestPost(uri: String, json: String) {
60 | println("Sending request to ${Configuration.baseUrl + uri} with body $json")
61 | HttpClient.newHttpClient().sendAsync(
62 | HttpRequest.newBuilder(URI.create(Configuration.baseUrl + uri))
63 | .POST(HttpRequest.BodyPublishers.ofString(json))
64 | .build(),
65 | HttpResponse.BodyHandlers.ofString()
66 | ).join().let { Datastore.statusCode(it.statusCode()) }
67 | }
68 |
69 | @Step("The response status code should be ")
70 | fun assertStatusCode(statusCode: Int) {
71 | Datastore.statusCode()?.let { assert(it == statusCode) }
72 | }
73 | }
--------------------------------------------------------------------------------
/e2e/src/test/resources/config.properties:
--------------------------------------------------------------------------------
1 | baseUrl=http://localhost:8080
--------------------------------------------------------------------------------
/examples/testcontainers-java/.gitignore:
--------------------------------------------------------------------------------
1 | target/
2 | !.mvn/wrapper/maven-wrapper.jar
3 | !**/src/main/**/target/
4 | !**/src/test/**/target/
5 |
6 | ### IntelliJ IDEA ###
7 | .idea/modules.xml
8 | .idea/jarRepositories.xml
9 | .idea/compiler.xml
10 | .idea/libraries/
11 | *.iws
12 | *.iml
13 | *.ipr
14 |
15 | ### Eclipse ###
16 | .apt_generated
17 | .classpath
18 | .factorypath
19 | .project
20 | .settings
21 | .springBeans
22 | .sts4-cache
23 |
24 | ### NetBeans ###
25 | /nbproject/private/
26 | /nbbuild/
27 | /dist/
28 | /nbdist/
29 | /.nb-gradle/
30 | build/
31 | !**/src/main/**/build/
32 | !**/src/test/**/build/
33 |
34 | ### VS Code ###
35 | .vscode/
36 |
37 | ### Mac OS ###
38 | .DS_Store
--------------------------------------------------------------------------------
/examples/testcontainers-java/README.md:
--------------------------------------------------------------------------------
1 | # Wiremock Graphql Extension Example - testcontainers-java
2 |
3 | This example shows how to use the Wiremock Graphql Extension with java and Testcontainers.
4 |
5 | ## Requirements
6 | - Java 17
7 | - Maven 3
8 | - Docker
9 |
10 | ## Run
11 | ```bash
12 | mvn test
13 | ```
--------------------------------------------------------------------------------
/examples/testcontainers-java/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | testcontainers-java-example
8 | org.example
9 | testcontainers-java
10 | 1.0-SNAPSHOT
11 |
12 |
13 | 17
14 | 17
15 | UTF-8
16 | 1.0-alpha-13
17 | 1.19.0
18 | 0.9.0
19 | 3.3.1
20 | 5.10.1
21 |
22 |
23 |
24 |
25 | mavenCentral
26 | https://repo1.maven.org/maven2/
27 |
28 |
29 | jitpack.io
30 | https://jitpack.io
31 |
32 |
33 |
34 |
35 |
36 |
37 | org.junit.jupiter
38 | junit-jupiter-api
39 | ${junit.version}
40 | test
41 |
42 |
43 | org.junit.jupiter
44 | junit-jupiter-engine
45 | ${junit.version}
46 | test
47 |
48 |
49 | org.wiremock
50 | wiremock
51 | ${wiremock.version}
52 | test
53 |
54 |
55 | com.github.wiremock
56 | wiremock-testcontainers-java
57 | ${wiremock.testcontainers.version}
58 | test
59 |
60 |
61 | org.testcontainers
62 | testcontainers
63 | ${testcontainers.version}
64 | test
65 |
66 |
67 | org.testcontainers
68 | junit-jupiter
69 | ${testcontainers.version}
70 | test
71 |
72 |
73 | io.github.nilwurtz
74 | wiremock-graphql-extension
75 | ${extension.version}
76 | test
77 |
78 |
79 |
80 |
81 | src/test/java
82 |
83 |
84 | org.apache.maven.plugins
85 | maven-dependency-plugin
86 | 3.5.0
87 |
88 |
89 | copy
90 | test-compile
91 |
92 | copy
93 |
94 |
95 |
96 |
97 | io.github.nilwurtz
98 | wiremock-graphql-extension
99 | ${extension.version}
100 | jar-with-dependencies
101 |
102 | wiremock-graphql-extension-jar-with-dependencies.jar
103 | true
104 |
105 |
106 | ${project.build.directory}/test-wiremock-extension
107 |
108 |
109 |
110 |
111 |
112 | maven-surefire-plugin
113 | 3.1.2
114 |
115 |
116 | maven-failsafe-plugin
117 | 3.1.2
118 |
119 |
120 |
121 |
--------------------------------------------------------------------------------
/examples/testcontainers-java/src/test/java/TestSample.java:
--------------------------------------------------------------------------------
1 | import com.github.tomakehurst.wiremock.client.WireMock;
2 | import io.github.nilwurtz.GraphqlBodyMatcher;
3 | import org.testcontainers.junit.jupiter.Container;
4 | import org.testcontainers.junit.jupiter.Testcontainers;
5 | import org.testcontainers.utility.DockerImageName;
6 | import org.wiremock.integrations.testcontainers.WireMockContainer;
7 | import org.junit.jupiter.api.Test;
8 |
9 | import java.io.IOException;
10 | import java.net.http.HttpClient;
11 | import java.net.http.HttpResponse;
12 | import java.nio.file.Paths;
13 | import java.util.Collections;
14 | import java.util.Map;
15 |
16 | import static org.junit.jupiter.api.Assertions.*;
17 |
18 | @Testcontainers
19 | public class TestSample {
20 |
21 | private static final String RESPONSE = """
22 | {
23 | "data": {
24 | "id": 1,
25 | "name": "test"
26 | }
27 | }
28 | """;
29 | @Container
30 | private static final WireMockContainer wiremockContainer = new WireMockContainer(
31 | DockerImageName.parse(WireMockContainer.OFFICIAL_IMAGE_NAME)
32 | .withTag("3.3.1")
33 | ).withExtensions(
34 | GraphqlBodyMatcher.extensionName,
35 | Collections.singleton("io.github.nilwurtz.GraphqlBodyMatcher"),
36 | Collections.singleton(
37 | Paths.get(
38 | "target",
39 | "test-wiremock-extension",
40 | "wiremock-graphql-extension-jar-with-dependencies.jar"
41 | ).toFile()
42 | )
43 | );
44 |
45 | @Test
46 | public void testRunning() {
47 | assertTrue(wiremockContainer.isRunning());
48 | }
49 |
50 | @Test
51 | public void testMatches() throws IOException, InterruptedException {
52 | var query = """
53 | query {
54 | name
55 | id
56 | }
57 | """;
58 | new WireMock(wiremockContainer.getPort()).register(
59 | WireMock.post(WireMock.urlEqualTo("/graphql"))
60 | .andMatching(
61 | GraphqlBodyMatcher.extensionName,
62 | GraphqlBodyMatcher.parameters(query))
63 | .willReturn(WireMock.okJson(RESPONSE)));;
64 |
65 |
66 | var client = HttpClient.newHttpClient();
67 | var request = java.net.http.HttpRequest.newBuilder()
68 | .uri(java.net.URI.create(wiremockContainer.getBaseUrl() + "/graphql"))
69 | .POST(java.net.http.HttpRequest.BodyPublishers.ofString("""
70 | { "query": "query { id name }" }"""))
71 | .build();
72 | var response = client.send(request, HttpResponse.BodyHandlers.ofString());
73 |
74 | assertEquals(200, response.statusCode());
75 | assertEquals(RESPONSE, response.body());
76 | }
77 |
78 | @Test
79 | public void testMatchesVariables() throws IOException, InterruptedException {
80 | var query = """
81 | query {
82 | name
83 | id
84 | }
85 | """;
86 | var variables = Map.of("id", 1);
87 | new WireMock(wiremockContainer.getPort()).register(
88 | WireMock.post(WireMock.urlEqualTo("/graphql"))
89 | .andMatching(
90 | GraphqlBodyMatcher.extensionName,
91 | GraphqlBodyMatcher.parameters(query, variables)
92 | )
93 | .willReturn(WireMock.okJson(RESPONSE)));
94 |
95 |
96 | var client = HttpClient.newHttpClient();
97 | var request = java.net.http.HttpRequest.newBuilder()
98 | .uri(java.net.URI.create(wiremockContainer.getBaseUrl() + "/graphql"))
99 | .POST(java.net.http.HttpRequest.BodyPublishers.ofString("""
100 | {"query": "query { id name }", "variables": {"id": 1}}"""))
101 | .build();
102 | var response = client.send(request, HttpResponse.BodyHandlers.ofString());
103 |
104 | assertEquals(200, response.statusCode());
105 | assertEquals(RESPONSE, response.body());
106 | }
107 |
108 | @Test
109 | public void testMatchesVariablesAndOperationName() throws IOException, InterruptedException {
110 | var query = """
111 | query {
112 | name
113 | id
114 | }
115 | """;
116 | var variables = Map.of("id", 1);
117 | var operationName = "operationName";
118 | new WireMock(wiremockContainer.getPort()).register(
119 | WireMock.post(WireMock.urlEqualTo("/graphql"))
120 | .andMatching(
121 | GraphqlBodyMatcher.extensionName,
122 | GraphqlBodyMatcher.parameters(query, variables, operationName)
123 | )
124 | .willReturn(WireMock.okJson(RESPONSE)));
125 |
126 |
127 | var client = HttpClient.newHttpClient();
128 | var request = java.net.http.HttpRequest.newBuilder()
129 | .uri(java.net.URI.create(wiremockContainer.getBaseUrl() + "/graphql"))
130 | .POST(java.net.http.HttpRequest.BodyPublishers.ofString("""
131 | {"query": "query { id name }", "variables": {"id": 1}, "operationName": "operationName"}"""))
132 | .build();
133 | var response = client.send(request, HttpResponse.BodyHandlers.ofString());
134 |
135 | assertEquals(200, response.statusCode());
136 | assertEquals(RESPONSE, response.body());
137 | }
138 | }
--------------------------------------------------------------------------------
/examples/testcontainers-kotlin/.gitignore:
--------------------------------------------------------------------------------
1 | target/
2 | !.mvn/wrapper/maven-wrapper.jar
3 | !**/src/main/**/target/
4 | !**/src/test/**/target/
5 |
6 | ### IntelliJ IDEA ###
7 | .idea/modules.xml
8 | .idea/jarRepositories.xml
9 | .idea/compiler.xml
10 | .idea/libraries/
11 | *.iws
12 | *.iml
13 | *.ipr
14 |
15 | ### Eclipse ###
16 | .apt_generated
17 | .classpath
18 | .factorypath
19 | .project
20 | .settings
21 | .springBeans
22 | .sts4-cache
23 |
24 | ### NetBeans ###
25 | /nbproject/private/
26 | /nbbuild/
27 | /dist/
28 | /nbdist/
29 | /.nb-gradle/
30 | build/
31 | !**/src/main/**/build/
32 | !**/src/test/**/build/
33 |
34 | ### VS Code ###
35 | .vscode/
36 |
37 | ### Mac OS ###
38 | .DS_Store
--------------------------------------------------------------------------------
/examples/testcontainers-kotlin/README.md:
--------------------------------------------------------------------------------
1 | # Wiremock Graphql Extension Example - testcontainers-kotlin
2 |
3 | This example shows how to use the Wiremock Graphql Extension with Kotlin and Testcontainers.
4 |
5 | ## Requirements
6 | - Java 17
7 | - Maven 3
8 | - Docker
9 |
10 | ## Run
11 | ```bash
12 | mvn test
13 | ```
--------------------------------------------------------------------------------
/examples/testcontainers-kotlin/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | testcontainers-kotlin
8 | org.example
9 | 1.0-SNAPSHOT
10 | jar
11 |
12 | testcontainers-kotlin-example
13 |
14 |
15 | UTF-8
16 | official
17 | 17
18 | 17
19 | 17
20 | 1.0-alpha-13
21 | 1.19.0
22 | 1.9.20
23 | 0.9.0
24 | 3.3.1
25 | 5.10.1
26 |
27 |
28 |
29 |
30 | mavenCentral
31 | https://repo1.maven.org/maven2/
32 |
33 |
34 | jitpack.io
35 | https://jitpack.io
36 |
37 |
38 |
39 |
40 | src/test/kotlin
41 |
42 |
43 | org.jetbrains.kotlin
44 | kotlin-maven-plugin
45 | ${kotlin.version}
46 |
47 |
48 | compile
49 | compile
50 |
51 | compile
52 |
53 |
54 |
55 | test-compile
56 | test-compile
57 |
58 | test-compile
59 |
60 |
61 |
62 | src/test/kotlin
63 |
64 |
65 |
66 |
67 |
68 |
69 | org.apache.maven.plugins
70 | maven-dependency-plugin
71 | 3.5.0
72 |
73 |
74 | copy
75 | test-compile
76 |
77 | copy
78 |
79 |
80 |
81 |
82 | io.github.nilwurtz
83 | wiremock-graphql-extension
84 | ${extension.version}
85 | jar-with-dependencies
86 |
87 | wiremock-graphql-extension-jar-with-dependencies.jar
88 | true
89 |
90 |
91 | ${project.build.directory}/test-wiremock-extension
92 |
93 |
94 |
95 |
96 |
97 | maven-surefire-plugin
98 | 3.2.2
99 |
100 |
101 | maven-failsafe-plugin
102 | 3.2.2
103 |
104 |
105 |
106 |
107 |
108 |
109 | org.junit.jupiter
110 | junit-jupiter-api
111 | ${junit.version}
112 | test
113 |
114 |
115 | org.junit.jupiter
116 | junit-jupiter-engine
117 | ${junit.version}
118 | test
119 |
120 |
121 | org.jetbrains.kotlin
122 | kotlin-stdlib
123 | ${kotlin.version}
124 |
125 |
126 | org.wiremock
127 | wiremock
128 | ${wiremock.version}
129 | test
130 |
131 |
132 | com.github.wiremock
133 | wiremock-testcontainers-java
134 | ${wiremock.testcontainers.version}
135 | test
136 |
137 |
138 | org.testcontainers
139 | testcontainers
140 | ${testcontainers.version}
141 | test
142 |
143 |
144 | org.testcontainers
145 | junit-jupiter
146 | ${testcontainers.version}
147 | test
148 |
149 |
150 | io.github.nilwurtz
151 | wiremock-graphql-extension
152 | ${extension.version}
153 | test
154 |
155 |
156 |
157 |
--------------------------------------------------------------------------------
/examples/testcontainers-kotlin/src/test/kotlin/TestSample.kt:
--------------------------------------------------------------------------------
1 | import com.github.tomakehurst.wiremock.client.WireMock
2 | import io.github.nilwurtz.GraphqlBodyMatcher
3 | import org.junit.jupiter.api.Assertions.*
4 | import org.junit.jupiter.api.Test
5 | import org.testcontainers.junit.jupiter.Container
6 | import org.testcontainers.junit.jupiter.Testcontainers
7 | import org.testcontainers.utility.DockerImageName
8 | import org.wiremock.integrations.testcontainers.WireMockContainer
9 | import java.net.http.HttpClient
10 | import java.nio.file.Paths
11 | import java.util.*
12 |
13 | @Testcontainers
14 | class TestSample {
15 |
16 | @Container
17 | val wireMockContainer: WireMockContainer =
18 | WireMockContainer(
19 | DockerImageName.parse(WireMockContainer.OFFICIAL_IMAGE_NAME + ":3.3.1")
20 | )
21 | .withExtensions(
22 | GraphqlBodyMatcher.extensionName,
23 | Collections.singleton("io.github.nilwurtz.GraphqlBodyMatcher"),
24 | Collections.singleton(
25 | Paths.get(
26 | "target",
27 | "test-wiremock-extension",
28 | "wiremock-graphql-extension-jar-with-dependencies.jar"
29 | ).toFile()
30 | )
31 | )
32 |
33 | @Test
34 | fun testRunning() {
35 | assertTrue { wireMockContainer.isRunning }
36 | }
37 |
38 | @Test
39 | fun testMatches() {
40 | val query = """
41 | query {
42 | name
43 | id
44 | }
45 | """.trimIndent()
46 | WireMock(wireMockContainer.port).register(
47 | WireMock.post(WireMock.urlEqualTo("/graphql"))
48 | .andMatching(
49 | GraphqlBodyMatcher.extensionName,
50 | GraphqlBodyMatcher.parameters(query)
51 | )
52 | .willReturn(WireMock.okJson("""{"data": {"id": 1, "name": "test"}}"""))
53 | )
54 |
55 |
56 | val client = HttpClient.newHttpClient()
57 | val request = java.net.http.HttpRequest.newBuilder()
58 | .uri(java.net.URI.create("${wireMockContainer.baseUrl}/graphql"))
59 | .POST(java.net.http.HttpRequest.BodyPublishers.ofString("""{"query": "query { id name }"}"""))
60 | .build().let { client.send(it, java.net.http.HttpResponse.BodyHandlers.ofString()) }
61 |
62 | assertEquals(200, request.statusCode())
63 | assertEquals("""{"data": {"id": 1, "name": "test"}}""", request.body())
64 | }
65 |
66 | @Test
67 | fun testMatchesVariables() {
68 | val query = """
69 | query {
70 | name
71 | id
72 | }
73 | """.trimIndent()
74 | val variables = mapOf("id" to 1)
75 | WireMock(wireMockContainer.port).register(
76 | WireMock.post(WireMock.urlEqualTo("/graphql"))
77 | .andMatching(
78 | GraphqlBodyMatcher.extensionName,
79 | GraphqlBodyMatcher.parameters(query, variables)
80 | )
81 | .willReturn(WireMock.okJson("""{"data": {"id": 1, "name": "test"}}"""))
82 | )
83 |
84 | val client = HttpClient.newHttpClient()
85 | val request = java.net.http.HttpRequest.newBuilder()
86 | .uri(java.net.URI.create("${wireMockContainer.baseUrl}/graphql"))
87 | .POST(java.net.http.HttpRequest.BodyPublishers.ofString("""{"query": "query { id name }", "variables": {"id": 1}}"""))
88 | .build().let { client.send(it, java.net.http.HttpResponse.BodyHandlers.ofString()) }
89 |
90 | assertEquals(200, request.statusCode())
91 | assertEquals("""{"data": {"id": 1, "name": "test"}}""", request.body())
92 | }
93 |
94 | @Test
95 | fun testMatchesVariablesAndOperationName() {
96 | val query = """
97 | query {
98 | name
99 | id
100 | }
101 | """.trimIndent()
102 | val variables = mapOf("id" to 1)
103 | val operationName = "operationName"
104 | WireMock(wireMockContainer.port).register(
105 | WireMock.post(WireMock.urlEqualTo("/graphql"))
106 | .andMatching(
107 | GraphqlBodyMatcher.extensionName,
108 | GraphqlBodyMatcher.parameters(query, variables, operationName)
109 | )
110 | .willReturn(WireMock.okJson("""{"data": {"id": 1, "name": "test"}}"""))
111 | )
112 |
113 | val client = HttpClient.newHttpClient()
114 | val request = java.net.http.HttpRequest.newBuilder()
115 | .uri(java.net.URI.create("${wireMockContainer.baseUrl}/graphql"))
116 | .POST(java.net.http.HttpRequest.BodyPublishers.ofString("""{"query": "query { id name }", "variables": {"id": 1}, "operationName": "operationName"}"""))
117 | .build().let { client.send(it, java.net.http.HttpResponse.BodyHandlers.ofString()) }
118 |
119 | assertEquals(200, request.statusCode())
120 | assertEquals("""{"data": {"id": 1, "name": "test"}}""", request.body())
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/wiremock-graphql-extension/.dockerignore:
--------------------------------------------------------------------------------
1 | target
2 | Dockerfile
--------------------------------------------------------------------------------
/wiremock-graphql-extension/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM maven:3.6.3-jdk-11-slim AS build
2 | WORKDIR /app
3 | COPY . .
4 | RUN mvn --batch-mode clean package -Dmaven.test.skip=true
5 |
6 | FROM wiremock/wiremock:latest AS wiremock
7 | COPY --from=build /app/target/wiremock-graphql-extension-*-jar-with-dependencies.jar /var/wiremock/extensions/wiremock-graphql-extension-jar-with-dependencies.jar
8 |
--------------------------------------------------------------------------------
/wiremock-graphql-extension/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | wiremock-graphql-extension
8 | io.github.nilwurtz
9 | 0.9.0
10 | jar
11 | wiremock-graphql-extension
12 | A WireMock extension for handling GraphQL requests, allowing for easy mocking of GraphQL APIs in
13 | integration tests and development environments.
14 |
15 | https://github.com/nilwurtz/wiremock-graphql-extension
16 |
17 |
18 |
19 | nilwurtz
20 | nilwurtz
21 | apollo.oth@gmail.com
22 | https://github.com/nilwurtz
23 |
24 |
25 |
26 |
27 | MIT License
28 | https://opensource.org/licenses/mit-license.php
29 |
30 |
31 |
32 |
33 | UTF-8
34 | official
35 | 11
36 | 11
37 | 11
38 | true
39 | 1.9.21
40 | 5.11.1
41 | 3.9.0
42 | 22.3
43 | 1.13.12
44 | 1.0-alpha-13
45 | 1.20.2
46 |
47 |
48 |
49 |
50 | mavenCentral
51 | https://repo1.maven.org/maven2/
52 |
53 |
54 | jitpack.io
55 | https://jitpack.io
56 |
57 |
58 |
59 |
60 |
61 | org.junit.jupiter
62 | junit-jupiter-api
63 | ${junit.version}
64 | test
65 |
66 |
67 | org.junit.jupiter
68 | junit-jupiter-engine
69 | ${junit.version}
70 | test
71 |
72 |
73 | org.jetbrains.kotlin
74 | kotlin-stdlib
75 | ${kotlin.version}
76 |
77 |
78 | org.wiremock
79 | wiremock
80 | ${wiremock.version}
81 |
82 |
83 | io.mockk
84 | mockk-jvm
85 | ${mockk.version}
86 | test
87 |
88 |
89 | com.graphql-java
90 | graphql-java
91 | ${graphql-java.version}
92 |
93 |
94 | com.github.wiremock
95 | wiremock-testcontainers-java
96 | ${wiremock.testcontainers.version}
97 | test
98 |
99 |
100 | org.testcontainers
101 | testcontainers
102 | ${testcontainers.version}
103 | test
104 |
105 |
106 | org.testcontainers
107 | junit-jupiter
108 | ${testcontainers.version}
109 | test
110 |
111 |
112 |
113 |
114 | src/main/kotlin
115 | src/test/kotlin
116 |
117 |
118 | org.jetbrains.kotlin
119 | kotlin-maven-plugin
120 | ${kotlin.version}
121 |
122 |
123 | compile
124 | compile
125 |
126 | compile
127 |
128 |
129 |
130 | test-compile
131 | test-compile
132 |
133 | test-compile
134 |
135 |
136 |
137 |
138 |
139 | maven-surefire-plugin
140 | 2.22.2
141 |
142 |
143 | maven-failsafe-plugin
144 | 2.22.2
145 |
146 |
147 | org.apache.maven.plugins
148 | maven-gpg-plugin
149 | 1.6
150 |
151 |
152 | sign-artifacts
153 | verify
154 |
155 | sign
156 |
157 |
158 |
159 |
160 |
161 |
162 | --pinentry-mode
163 | loopback
164 |
165 | ${gpg.skip}
166 |
167 |
168 |
169 | org.apache.maven.plugins
170 | maven-source-plugin
171 | 3.2.1
172 |
173 |
174 | attach-sources
175 |
176 | jar
177 |
178 |
179 |
180 |
181 |
182 | org.jetbrains.dokka
183 | dokka-maven-plugin
184 | 1.8.10
185 |
186 |
187 | prepare-package
188 |
189 | dokka
190 | javadoc
191 | javadocJar
192 |
193 |
194 |
195 |
196 |
197 |
198 | org.jetbrains.dokka
199 | kotlin-as-java-plugin
200 | 1.8.10
201 |
202 |
203 |
204 |
205 |
206 | org.sonatype.plugins
207 | nexus-staging-maven-plugin
208 | 1.6.13
209 | true
210 |
211 | ossrh
212 | https://s01.oss.sonatype.org
213 | true
214 |
215 |
216 |
217 | maven-assembly-plugin
218 |
219 |
220 | package
221 |
222 | single
223 |
224 |
225 |
226 | make-assembly
227 | process-test-classes
228 |
229 | single
230 |
231 |
232 |
233 |
234 | io.github.nilwurtz.GraphqlBodyMatcher
235 |
236 |
237 |
238 | jar-with-dependencies
239 |
240 |
241 |
242 |
243 |
244 |
245 | jar-with-dependencies
246 |
247 |
248 |
249 |
250 | org.apache.maven.plugins
251 | maven-dependency-plugin
252 |
253 |
254 | copy
255 | process-test-classes
256 |
257 | copy
258 |
259 |
260 |
261 |
262 | ${project.groupId}
263 | ${project.artifactId}
264 | ${project.version}
265 | jar-with-dependencies
266 | wiremock-graphql-extension.jar
267 | true
268 |
269 |
270 | ${project.build.directory}/test-wiremock-extension
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 | ossrh
281 | https://s01.oss.sonatype.org/content/repositories/snapshots
282 |
283 |
284 | ossrh
285 | https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/
286 |
287 |
288 |
289 |
290 | scm:git:https://github.com/nilwurtz/wiremock-graphql-extension.git
291 | scm:git:https://github.com/nilwurtz/wiremock-graphql-extension.git
292 | https://github.com/nilwurtz/wiremock-graphql-extension
293 |
294 |
295 |
--------------------------------------------------------------------------------
/wiremock-graphql-extension/src/main/kotlin/io/github/nilwurtz/EqualToGraphqlQueryPattern.kt:
--------------------------------------------------------------------------------
1 | package io.github.nilwurtz
2 |
3 | import com.github.tomakehurst.wiremock.matching.ContentPattern
4 | import com.github.tomakehurst.wiremock.matching.MatchResult
5 | import com.github.tomakehurst.wiremock.stubbing.SubEvent
6 | import graphql.language.AstComparator
7 | import graphql.language.AstSorter
8 | import graphql.language.Document
9 | import graphql.parser.InvalidSyntaxException
10 | import graphql.parser.Parser
11 |
12 | class EqualToGraphqlQueryPattern(expectedValue: String) : ContentPattern(expectedValue) {
13 |
14 | private val expectedDocument = expectedValue.parse().sort()
15 |
16 | override fun match(requestValue: String?): MatchResult {
17 | return try {
18 | val requestDocument = requestValue?.parse()?.sort()
19 | if (AstComparator.isEqual(expectedDocument, requestDocument)) {
20 | MatchResult.exactMatch()
21 | } else {
22 | MatchResult.noMatch()
23 | }
24 | } catch (e: InvalidSyntaxException) {
25 | MatchResult.noMatch(SubEvent.warning(e.message))
26 | }
27 | }
28 |
29 | override fun getName(): String {
30 | return "equalToGraphqlQuery"
31 | }
32 |
33 | override fun getExpected(): String {
34 | return expectedValue
35 | }
36 | }
37 |
38 | private fun String.parse(): Document {
39 | return Parser().parseDocument(this)
40 | }
41 |
42 | private fun Document.sort(): Document {
43 | return AstSorter().sort(this);
44 | }
45 |
--------------------------------------------------------------------------------
/wiremock-graphql-extension/src/main/kotlin/io/github/nilwurtz/GraphqlBodyMatcher.kt:
--------------------------------------------------------------------------------
1 | package io.github.nilwurtz
2 |
3 | import com.github.tomakehurst.wiremock.common.Json
4 | import com.github.tomakehurst.wiremock.common.JsonException
5 | import com.github.tomakehurst.wiremock.extension.Parameters
6 | import com.github.tomakehurst.wiremock.http.Request
7 | import com.github.tomakehurst.wiremock.matching.AbsentPattern
8 | import com.github.tomakehurst.wiremock.matching.EqualToJsonPattern
9 | import com.github.tomakehurst.wiremock.matching.EqualToPattern
10 | import com.github.tomakehurst.wiremock.matching.MatchResult
11 | import com.github.tomakehurst.wiremock.matching.RequestMatcherExtension
12 | import com.github.tomakehurst.wiremock.matching.StringValuePattern
13 | import com.github.tomakehurst.wiremock.stubbing.SubEvent
14 | import graphql.parser.InvalidSyntaxException
15 | import graphql.parser.Parser
16 |
17 |
18 | class GraphqlBodyMatcher() : RequestMatcherExtension() {
19 |
20 | companion object {
21 | const val extensionName = "graphql-body-matcher"
22 |
23 | /**
24 | * Creates a new instance of [GraphqlBodyMatcher] with the given GraphQL query string and variables.
25 | * The query string and variables are wrapped in a JSON object with "query" and "variables" fields, parsed, validated,
26 | * and normalized before being used for matching.
27 | *
28 | * @param expectedQuery The GraphQL query string that the matcher expects in requests.
29 | * @param expectedVariables The variables associated with the GraphQL query as a JSON string.
30 | * @return A new [GraphqlBodyMatcher] instance with the given expected query and variables.
31 | * @throws JsonException if the generated JSON is malformed.
32 | * @throws InvalidSyntaxException if the given query is invalid.
33 | */
34 | @Deprecated("Use parameters instead. Along with Wiremock.requestMatching(String, Parameters) or MappingBuilder#andMatching(String, Parameters).")
35 | @JvmStatic
36 | @JvmOverloads
37 | fun withRequestQueryAndVariables(expectedQuery: String, expectedVariables: String? = null): GraphqlBodyMatcher {
38 | // Avoid to parse json here. It will be parsed in initExpectedRequestJson
39 | return GraphqlBodyMatcher().apply {
40 | val variablesJsonOrEmptyString =
41 | if (expectedVariables != null) ""","variables": $expectedVariables""" else ""
42 | initParameters(withRequest("""{"query": "$expectedQuery"$variablesJsonOrEmptyString}"""))
43 | }
44 | }
45 |
46 | /**
47 | * Creates a new instance of [GraphqlBodyMatcher] with the given raw JSON string containing a
48 | * GraphQL query and optional variables. The JSON is expected to have a "query" field with the query string
49 | * and an optional "variables" field containing the variables.
50 | * The query is parsed, validated, and normalized before being used for matching.
51 | *
52 | * @param expectedJson The raw JSON string containing the GraphQL query and optional variables that the matcher expects in requests.
53 | * @return A new [GraphqlBodyMatcher] instance with the given expected query and variables.
54 | * @throws JsonException if the given JSON is malformed.
55 | * @throws InvalidSyntaxException if the given query is invalid.
56 | */
57 | @Deprecated("Use parameters instead. Along with Wiremock.requestMatching(String, Parameters) or MappingBuilder#andMatching(String, Parameters).")
58 | @JvmStatic
59 | fun withRequestJson(expectedJson: String): GraphqlBodyMatcher {
60 | return GraphqlBodyMatcher().apply {
61 | initParameters(withRequest(expectedJson))
62 | }
63 | }
64 |
65 | /**
66 | * Creates a Parameters instance containing the given raw JSON string expected in the GraphQL request.
67 | *
68 | * This method is used to set up JSON expected in remote requests. The expectedJson parameter should be a raw JSON string that encapsulates the expected query and optionally variables for the GraphQL request. This string is used to create a parameters object utilized internally in the GraphqlBodyMatcher.
69 | *
70 | * @param expectedJson A raw JSON string that contains the GraphQL query and optionally variables expected in the requests.
71 | * @return A Parameters instance created based on the expected JSON string.
72 | * @throws JsonException if the given JSON is malformed.
73 | * @throws InvalidSyntaxException if the given query is invalid.
74 | */
75 | @Deprecated("Use parameters instead.")
76 | @JvmStatic
77 | fun withRequest(expectedJson: String): Parameters {
78 | val expectedJsonObject = Json.read(expectedJson.replace("\n", ""), Map::class.java)
79 | return parameters(
80 | expectedJsonObject["query"] as String,
81 | expectedJsonObject["variables"] as Map?,
82 | expectedJsonObject["operationName"] as String?)
83 | }
84 |
85 | /**
86 | * Creates a Parameters instance containing the query and optionally the variables and operationName.
87 | *
88 | * @param query A GraphQL query string.
89 | * @param variables An optional map of variables used in the GraphQL query.
90 | * @param operationName The optional name of the operation in the GraphQL query.
91 | * @return A Parameters instance containing the query and optionally the variables and operationName.
92 | * @throws InvalidSyntaxException if the given query is invalid.
93 | * @see GraphQL Queries and Mutations
94 | * @see GraphQL Variables
95 | * @see GraphQL Operation Name
96 | */
97 | @JvmStatic
98 | @JvmOverloads
99 | fun parameters(query: String, variables: Map? = null, operationName: String? = null): Parameters {
100 | Parser().parseDocument(query)
101 | return Parameters.one("query", query).apply {
102 | variables?.let { put("variables", it) }
103 | operationName?.let { put("operationName", it) }
104 | }
105 | }
106 | }
107 |
108 | private lateinit var parameters: Parameters
109 |
110 | private fun initParameters(parameters: Parameters) {
111 | this.parameters = parameters
112 | }
113 |
114 | /**
115 | * Compares the given [Request] against the expected GraphQL query, variables, and operationName to determine if
116 | * they match. If query, variables, and operationName are semantically equal, it returns an exact match result;
117 | * otherwise, it returns a no match result.
118 | *
119 | * @param request The incoming request to match against the expected query and variables.
120 | * @param parameters Additional parameters that may be used for matching.
121 | * @return [MatchResult.exactMatch] if the request query and variables match the expected query and variables,
122 | * [MatchResult.noMatch] otherwise.
123 | */
124 | override fun match(request: Request, parameters: Parameters): MatchResult {
125 | try {
126 | // for local call
127 | if (parameters.isEmpty()) {
128 | parameters.putAll(this.parameters)
129 | }
130 | val expectedQuery = parameters.getString("query")
131 | val expectedVariables = parameters["variables"]?.writeJson()
132 | val expectedOperationName = parameters.getString("operationName", null)
133 |
134 | val requestJson = Json.read(request.bodyAsString, Map::class.java)
135 | val requestQuery = requestJson["query"] as String
136 | val requestVariables = requestJson["variables"]?.writeJson()
137 | val requestOperationName = requestJson["operationName"] as String?
138 |
139 | return MatchResult.aggregate(
140 | EqualToGraphqlQueryPattern(expectedQuery).match(requestQuery),
141 | variablesPattern(expectedVariables).match(requestVariables),
142 | operationNamePattern(expectedOperationName).match(requestOperationName)
143 | )
144 | } catch (e: Exception) {
145 | return MatchResult.noMatch(SubEvent.warning(e.message))
146 | }
147 | }
148 |
149 | private fun variablesPattern(expectedVariables: String?) : StringValuePattern {
150 | return if (expectedVariables == null) {
151 | AbsentPattern.ABSENT
152 | } else {
153 | EqualToJsonPattern(expectedVariables, false, false)
154 | }
155 | }
156 |
157 | private fun operationNamePattern(expectedOperationName: String?) : StringValuePattern {
158 | return if (expectedOperationName == null) {
159 | AbsentPattern.ABSENT
160 | } else {
161 | EqualToPattern(expectedOperationName)
162 | }
163 | }
164 |
165 | override fun getName(): String {
166 | return extensionName
167 | }
168 | }
169 |
170 | private fun Any.writeJson(): String {
171 | return Json.write(this)
172 | }
173 |
--------------------------------------------------------------------------------
/wiremock-graphql-extension/src/main/resources/META-INF/services/com.github.tomakehurst.wiremock.extension.Extension:
--------------------------------------------------------------------------------
1 | io.github.nilwurtz.GraphqlBodyMatcher
2 |
--------------------------------------------------------------------------------
/wiremock-graphql-extension/src/test/kotlin/io/github/nilwurtz/EqualToGraphqlQueryPatternTest.kt:
--------------------------------------------------------------------------------
1 | package io.github.nilwurtz
2 |
3 | import graphql.parser.InvalidSyntaxException
4 | import org.junit.jupiter.api.Test
5 | import org.junit.jupiter.api.Assertions.*
6 |
7 | class EqualToGraphqlQueryPatternTest {
8 |
9 | @Test
10 | fun testMatchedIdentical() {
11 | val query = """
12 | {
13 | hero {
14 | name
15 | friends {
16 | name
17 | }
18 | }
19 | }
20 | """.trimIndent()
21 | val pattern = EqualToGraphqlQueryPattern(query)
22 | val result = pattern.match(query)
23 | assertTrue(result.isExactMatch)
24 | }
25 |
26 | @Test
27 | fun testMatchedDifferentOrderSingleLevel() {
28 | val query1 = """
29 | {
30 | hero {
31 | name
32 | age
33 | height
34 | }
35 | }
36 | """.trimIndent()
37 | val query2 = """
38 | {
39 | hero {
40 | age
41 | height
42 | name
43 | }
44 | }
45 | """.trimIndent()
46 | val pattern = EqualToGraphqlQueryPattern(query1)
47 | val result = pattern.match(query2)
48 | assertTrue(result.isExactMatch)
49 | }
50 |
51 | @Test
52 | fun testMatchedDifferentOrderNested() {
53 | val query1 = """
54 | {
55 | hero {
56 | name
57 | friends {
58 | name
59 | friends {
60 | name
61 | age
62 | }
63 | }
64 | }
65 | }
66 | """.trimIndent()
67 | val query2 = """
68 | {
69 | hero {
70 | name
71 | friends {
72 | name
73 | friends {
74 | age
75 | name
76 | }
77 | }
78 | }
79 | }
80 | """.trimIndent()
81 | val pattern = EqualToGraphqlQueryPattern(query1)
82 | val result = pattern.match(query2)
83 | assertTrue(result.isExactMatch)
84 | }
85 |
86 | @Test
87 | fun testUnmatchedDifferentDepth() {
88 | val query1 = """
89 | {
90 | hero {
91 | name
92 | friends {
93 | name
94 | }
95 | }
96 | }
97 | """.trimIndent()
98 | val query2 = """
99 | {
100 | hero {
101 | name
102 | friends {
103 | name {
104 | first
105 | last
106 | }
107 | }
108 | }
109 | }
110 | """.trimIndent()
111 | val pattern = EqualToGraphqlQueryPattern(query1)
112 | val result = pattern.match(query2)
113 | assertFalse(result.isExactMatch)
114 | }
115 |
116 | @Test
117 | fun testUnmatchedMissingField() {
118 | val query1 = """
119 | {
120 | hero {
121 | friends {
122 | name
123 | }
124 | }
125 | }
126 | """.trimIndent()
127 | val query2 = """
128 | {
129 | hero {
130 | name
131 | friends {
132 | name
133 | }
134 | }
135 | }
136 | """.trimIndent()
137 | val pattern = EqualToGraphqlQueryPattern(query1)
138 | val result = pattern.match(query2)
139 | assertFalse(result.isExactMatch)
140 | }
141 |
142 | @Test
143 | fun testUnmatchedAdditionalField() {
144 | val query1 = """
145 | {
146 | hero {
147 | name
148 | friends {
149 | name
150 | }
151 | }
152 | }
153 | """.trimIndent()
154 | val query2 = """
155 | {
156 | hero {
157 | name
158 | friends {
159 | namea
160 | }
161 | }
162 | }
163 | """.trimIndent()
164 | val pattern = EqualToGraphqlQueryPattern(query1)
165 | val result = pattern.match(query2)
166 | assertFalse(result.isExactMatch)
167 | }
168 |
169 | @Test
170 | fun testUnmatchedDifferentFieldName() {
171 | val query1 = """
172 | {
173 | hero {
174 | name
175 | friends {
176 | name
177 | }
178 | }
179 | }
180 | """.trimIndent()
181 | val query2 = """
182 | {
183 | hero {
184 | name
185 | friends {
186 | firstName
187 | }
188 | }
189 | }
190 | """.trimIndent()
191 | val pattern = EqualToGraphqlQueryPattern(query1)
192 | val result = pattern.match(query2)
193 | assertFalse(result.isExactMatch)
194 | }
195 |
196 | @Test
197 | fun testInvalidQuery() {
198 | val query = """
199 | {
200 | hero {
201 | name
202 | age
203 | height
204 | """.trimIndent()
205 | org.junit.jupiter.api.assertThrows {
206 | GraphqlBodyMatcher.parameters(query)
207 | }
208 | }
209 | }
210 |
--------------------------------------------------------------------------------
/wiremock-graphql-extension/src/test/kotlin/io/github/nilwurtz/GraphqlBodyMatcherTest.kt:
--------------------------------------------------------------------------------
1 | package io.github.nilwurtz
2 |
3 | import com.github.tomakehurst.wiremock.common.JsonException
4 | import org.junit.jupiter.api.DisplayName
5 | import org.junit.jupiter.api.Test
6 | import com.github.tomakehurst.wiremock.http.Request
7 | import com.github.tomakehurst.wiremock.extension.Parameters
8 | import graphql.parser.InvalidSyntaxException
9 | import io.mockk.every
10 | import io.mockk.mockk
11 | import org.junit.jupiter.api.Assertions.*
12 | import org.junit.jupiter.api.Nested
13 | import org.junit.jupiter.api.assertThrows
14 |
15 | class GraphqlBodyMatcherTest {
16 |
17 | companion object {
18 | const val QUERY = "{ query }"
19 | const val WRONG_QUERY = "{ wrong }";
20 | const val VARIABLES = """
21 | {
22 | "abc": 123
23 | }
24 | """
25 | const val WRONG_VARIABLES = """
26 | {
27 | "def": 456
28 | }
29 | """
30 | const val OPERATION_NAME = "operationName"
31 | const val WRONG_OPERATION_NAME = ""
32 | val VARIABLES_MAP = mapOf("abc" to 123)
33 | }
34 |
35 | @Test
36 | fun testAllMatch() {
37 | val request = mockk()
38 | val json = """
39 | {
40 | "query": "$QUERY",
41 | "variables": $VARIABLES,
42 | "operationName": "$OPERATION_NAME"
43 | }
44 | """.trimIndent()
45 |
46 | every { request.bodyAsString } returns json
47 |
48 | val actual =
49 | GraphqlBodyMatcher().match(request, GraphqlBodyMatcher.parameters(QUERY, VARIABLES_MAP, OPERATION_NAME))
50 | assertTrue(actual.isExactMatch)
51 | }
52 |
53 | @Test
54 | fun testAllWithWrongQuery() {
55 | val request = mockk()
56 | val json = """
57 | {
58 | "query": "$WRONG_QUERY",
59 | "variables": $VARIABLES,
60 | "operationName": "$OPERATION_NAME"
61 | }
62 | """.trimIndent()
63 |
64 | every { request.bodyAsString } returns json
65 |
66 | val actual =
67 | GraphqlBodyMatcher().match(request, GraphqlBodyMatcher.parameters(QUERY, VARIABLES_MAP, OPERATION_NAME))
68 | assertFalse(actual.isExactMatch)
69 | assertEquals(1.0 / 3.0, actual.distance)
70 | }
71 |
72 | @Test
73 | fun testAllWithWrongVariables() {
74 | val request = mockk()
75 | val json = """
76 | {
77 | "query": "$QUERY",
78 | "variables": $WRONG_VARIABLES,
79 | "operationName": "$OPERATION_NAME"
80 | }
81 | """.trimIndent()
82 |
83 | every { request.bodyAsString } returns json
84 |
85 | val actual =
86 | GraphqlBodyMatcher().match(request, GraphqlBodyMatcher.parameters(QUERY, VARIABLES_MAP, OPERATION_NAME))
87 | assertFalse(actual.isExactMatch)
88 | assertEquals(1.0 / 3.0, actual.distance)
89 | }
90 |
91 | @Test
92 | fun testAllWithWrongOperationName() {
93 | val request = mockk()
94 | val json = """
95 | {
96 | "query": "$QUERY",
97 | "variables": $VARIABLES,
98 | "operationName": "$WRONG_OPERATION_NAME"
99 | }
100 | """.trimIndent()
101 |
102 | every { request.bodyAsString } returns json
103 |
104 | val actual =
105 | GraphqlBodyMatcher().match(request, GraphqlBodyMatcher.parameters(QUERY, VARIABLES_MAP, OPERATION_NAME))
106 | assertFalse(actual.isExactMatch)
107 | assertEquals(1.0 / 3.0, actual.distance)
108 | }
109 |
110 | @Test
111 | fun testOperationNameMatch() {
112 | val request = mockk()
113 | val json = """
114 | {
115 | "query": "$QUERY",
116 | "operationName": "$OPERATION_NAME"
117 | }
118 | """.trimIndent()
119 |
120 | every { request.bodyAsString } returns json
121 |
122 | val actual = GraphqlBodyMatcher().match(request, GraphqlBodyMatcher.parameters(QUERY, null, OPERATION_NAME))
123 | assertTrue(actual.isExactMatch)
124 | }
125 |
126 | @Test
127 | fun testOperationNameWithWrongQuery() {
128 | val request = mockk()
129 | val json = """
130 | {
131 | "query": "$WRONG_QUERY",
132 | "operationName": "$OPERATION_NAME"
133 | }
134 | """.trimIndent()
135 |
136 | every { request.bodyAsString } returns json
137 |
138 | val actual = GraphqlBodyMatcher().match(request, GraphqlBodyMatcher.parameters(QUERY, null, OPERATION_NAME))
139 | assertFalse(actual.isExactMatch)
140 | assertEquals(1.0 / 3.0, actual.distance)
141 | }
142 |
143 | @Test
144 | fun testOperationNameWithWrongVariables() {
145 | val request = mockk()
146 | val json = """
147 | {
148 | "query": "$QUERY",
149 | "variables": $WRONG_VARIABLES,
150 | "operationName": "$OPERATION_NAME"
151 | }
152 | """.trimIndent()
153 |
154 | every { request.bodyAsString } returns json
155 |
156 | val actual = GraphqlBodyMatcher().match(request, GraphqlBodyMatcher.parameters(QUERY, null, OPERATION_NAME))
157 | assertFalse(actual.isExactMatch)
158 | assertEquals(1.0 / 3.0, actual.distance)
159 | }
160 |
161 | @Test
162 | fun testOperationNameWithWrongOperationName() {
163 | val request = mockk()
164 | val json = """
165 | {
166 | "query": "$QUERY",
167 | "operationName": "$WRONG_OPERATION_NAME"
168 | }
169 | """.trimIndent()
170 |
171 | every { request.bodyAsString } returns json
172 |
173 | val actual = GraphqlBodyMatcher().match(request, GraphqlBodyMatcher.parameters(QUERY, null, OPERATION_NAME))
174 | assertFalse(actual.isExactMatch)
175 | assertEquals(1.0 / 3.0, actual.distance)
176 | }
177 |
178 | @Test
179 | fun testVariables() {
180 | val request = mockk()
181 | val json = """
182 | {
183 | "query": "$QUERY",
184 | "variables": $VARIABLES
185 | }
186 | """.trimIndent()
187 |
188 | every { request.bodyAsString } returns json
189 |
190 | val actual = GraphqlBodyMatcher().match(request, GraphqlBodyMatcher.parameters(QUERY, VARIABLES_MAP))
191 | assertTrue(actual.isExactMatch)
192 | }
193 |
194 | @Test
195 | fun testVariablesWithWrongQuery() {
196 | val request = mockk()
197 | val json = """
198 | {
199 | "query": "$WRONG_QUERY",
200 | "variables": $VARIABLES
201 | }
202 | """.trimIndent()
203 |
204 | every { request.bodyAsString } returns json
205 |
206 | val actual = GraphqlBodyMatcher().match(request, GraphqlBodyMatcher.parameters(QUERY, VARIABLES_MAP))
207 | assertFalse(actual.isExactMatch)
208 | assertEquals(1.0 / 3.0, actual.distance)
209 | }
210 |
211 | @Test
212 | fun testVariablesWithWrongVariables() {
213 | val request = mockk()
214 | val json = """
215 | {
216 | "query": "$QUERY",
217 | "variables": $WRONG_VARIABLES
218 | }
219 | """.trimIndent()
220 |
221 | every { request.bodyAsString } returns json
222 |
223 | val actual = GraphqlBodyMatcher().match(request, GraphqlBodyMatcher.parameters(QUERY, VARIABLES_MAP))
224 | assertFalse(actual.isExactMatch)
225 | assertEquals(1.0 / 3.0, actual.distance)
226 | }
227 |
228 | @Test
229 | fun testVariablesWithWrongOperationName() {
230 | val request = mockk()
231 | val json = """
232 | {
233 | "query": "$QUERY",
234 | "variables": $VARIABLES,
235 | "operationName": "$WRONG_OPERATION_NAME"
236 | }
237 | """.trimIndent()
238 |
239 | every { request.bodyAsString } returns json
240 |
241 | val actual = GraphqlBodyMatcher().match(request, GraphqlBodyMatcher.parameters(QUERY, VARIABLES_MAP))
242 | assertFalse(actual.isExactMatch)
243 | assertEquals(1.0 / 3.0, actual.distance)
244 | }
245 |
246 | @Test
247 | fun testQuery() {
248 | val request = mockk()
249 | val json = """
250 | {
251 | "query": "$QUERY"
252 | }
253 | """.trimIndent()
254 |
255 | every { request.bodyAsString } returns json
256 |
257 | val actual = GraphqlBodyMatcher().match(request, GraphqlBodyMatcher.parameters(QUERY))
258 | assertTrue(actual.isExactMatch)
259 | }
260 |
261 | @Test
262 | fun testQueryWithWrongQuery() {
263 | val request = mockk()
264 | val json = """
265 | {
266 | "query": "$WRONG_QUERY"
267 | }
268 | """.trimIndent()
269 |
270 | every { request.bodyAsString } returns json
271 |
272 | val actual = GraphqlBodyMatcher().match(request, GraphqlBodyMatcher.parameters(QUERY))
273 | assertFalse(actual.isExactMatch)
274 | assertEquals(1.0 / 3.0, actual.distance)
275 | }
276 |
277 | @Test
278 | fun testQueryWithWrongVariables() {
279 | val request = mockk()
280 | val json = """
281 | {
282 | "query": "$QUERY",
283 | "variables": $WRONG_VARIABLES
284 | }
285 | """.trimIndent()
286 |
287 | every { request.bodyAsString } returns json
288 |
289 | val actual = GraphqlBodyMatcher().match(request, GraphqlBodyMatcher.parameters(QUERY))
290 | assertFalse(actual.isExactMatch)
291 | assertEquals(1.0 / 3.0, actual.distance)
292 | }
293 |
294 | @Test
295 | fun testQueryWithWrongOperationName() {
296 | val request = mockk()
297 | val json = """
298 | {
299 | "query": "$QUERY",
300 | "operationName": "$WRONG_OPERATION_NAME"
301 | }
302 | """.trimIndent()
303 |
304 | every { request.bodyAsString } returns json
305 |
306 | val actual = GraphqlBodyMatcher().match(request, GraphqlBodyMatcher.parameters(QUERY))
307 | assertFalse(actual.isExactMatch)
308 | assertEquals(1.0 / 3.0, actual.distance)
309 | }
310 |
311 | @Nested
312 | @DisplayName("test `withRequestJson`")
313 | inner class WithRequestJsonTest {
314 | @Test
315 | @DisplayName("queries are identical")
316 | fun testMatchedIdentical() {
317 | val request = mockk()
318 | val parameters = Parameters()
319 | // language=json
320 | val json = """
321 | {
322 | "query": "{ hero { name friends { name }}}"
323 | }
324 | """.trimIndent()
325 |
326 | every { request.bodyAsString } returns json
327 |
328 | val actual = GraphqlBodyMatcher.withRequestJson(json).match(request, parameters)
329 | assertTrue(actual.isExactMatch)
330 | }
331 |
332 | @Test
333 | @DisplayName("query has different order in single level")
334 | fun testMatchedDifferentOrderSingleLevel() {
335 | val request = mockk()
336 | val parameters = Parameters()
337 | // language=JSON
338 | val requestJson = """
339 | {
340 | "query": "{ hero { name, age, height }}"
341 | }
342 | """.trimIndent()
343 | // language=JSON
344 | val expectedJson = """
345 | {
346 | "query": "{ hero { age, height, name }}"
347 | }
348 | """.trimIndent()
349 |
350 | every { request.bodyAsString } returns requestJson
351 |
352 | val actual = GraphqlBodyMatcher.withRequestJson(expectedJson).match(request, parameters)
353 | assertTrue(actual.isExactMatch)
354 | }
355 |
356 | @Test
357 | @DisplayName("graphql query has different order so nested")
358 | fun testMatchedDifferentOrderNested() {
359 | val request = mockk()
360 | val parameters = Parameters()
361 | // language=JSON
362 | val requestJson = """
363 | {
364 | "query": "{ hero { name friends { name friends { name age }}}}"
365 | }
366 | """.trimIndent()
367 | // language=JSON
368 | val expectedJson = """
369 | {
370 | "query": "{ hero { name friends { name friends { age name }}}}"
371 | }
372 | """.trimIndent()
373 |
374 | every { request.bodyAsString } returns requestJson
375 |
376 | val actual = GraphqlBodyMatcher.withRequestJson(expectedJson).match(request, parameters)
377 | assertTrue(actual.isExactMatch)
378 | }
379 |
380 | @Test
381 | @DisplayName("query has different depth")
382 | fun testUnmatchedDifferentDepth() {
383 | val request = mockk()
384 | val parameters = Parameters()
385 | // language=json
386 | val requestJson = """
387 | {
388 | "query": "{ hero { name friends { name }}}"
389 | }
390 | """.trimIndent()
391 | // language=json
392 | val expectedJson = """
393 | {
394 | "query": "{ hero { name friends { name { first last } }}}"
395 | }
396 | """.trimIndent()
397 |
398 | every { request.bodyAsString } returns requestJson
399 |
400 | val actual = GraphqlBodyMatcher.withRequestJson(expectedJson).match(request, parameters)
401 | assertFalse(actual.isExactMatch)
402 | }
403 |
404 | @Test
405 | @DisplayName("query is missing a field")
406 | fun testUnmatchedMissingField() {
407 | val request = mockk()
408 | val parameters = Parameters()
409 | // language=json
410 | val requestJson = """
411 | {
412 | "query": "{ hero { friends { name }}}"
413 | }
414 | """.trimIndent()
415 | // language=json
416 | val expectedJson = """
417 | {
418 | "query": "{ hero { name friends { name }}}"
419 | }
420 | """.trimIndent()
421 |
422 | every { request.bodyAsString } returns requestJson
423 |
424 | val actual = GraphqlBodyMatcher.withRequestJson(expectedJson).match(request, parameters)
425 | assertFalse(actual.isExactMatch)
426 | }
427 |
428 | @Test
429 | @DisplayName("query has additional field")
430 | fun testUnmatchedAdditionalField() {
431 | val request = mockk()
432 | val parameters = Parameters()
433 | // language=json
434 | val requestJson = """
435 | {
436 | "query": "{ hero { name friends { name }}}"
437 | }
438 | """.trimIndent()
439 | // language=json
440 | val expectedJson = """
441 | {
442 | "query": "{ hero { friends { name }}}"
443 | }
444 | """.trimIndent()
445 |
446 | every { request.bodyAsString } returns requestJson
447 |
448 | val actual = GraphqlBodyMatcher.withRequestJson(expectedJson).match(request, parameters)
449 | assertFalse(actual.isExactMatch)
450 | }
451 |
452 | @Test
453 | @DisplayName("query has different field name")
454 | fun testUnmatchedDifferentFieldName() {
455 | val request = mockk()
456 | val parameters = Parameters()
457 | // language=json
458 | val json1 = """
459 | {
460 | "query": "{ hero { name friends { name }}}"
461 | }
462 | """.trimIndent()
463 | // language=json
464 | val json2 = """
465 | {
466 | "query": "{ hero { name friends { namea }}}"
467 | }
468 | """.trimIndent()
469 |
470 | every { request.bodyAsString } returns json1
471 |
472 | val actual = GraphqlBodyMatcher.withRequestJson(json2).match(request, parameters)
473 | assertFalse(actual.isExactMatch)
474 | }
475 |
476 | @Test
477 | @DisplayName("query is invalid JSON")
478 | fun testUnmatchedInvalidJson() {
479 | val request = mockk()
480 | val parameters = Parameters()
481 | // language=json
482 | val invalidQuery = """
483 | {
484 | "query": "{ hero { name, age, height "
485 | }
486 | """.trimIndent()
487 |
488 | every { request.bodyAsString } returns invalidQuery
489 |
490 | assertThrows {
491 | GraphqlBodyMatcher.withRequestJson(invalidQuery).match(request, parameters)
492 | }
493 | }
494 |
495 | @Test
496 | @DisplayName("json is empty")
497 | fun testUnmatchedEmptyJson() {
498 | val request = mockk()
499 | val parameters = Parameters()
500 | val emptyJson = ""
501 |
502 | every { request.bodyAsString } returns emptyJson
503 |
504 | assertThrows {
505 | GraphqlBodyMatcher.withRequestJson(emptyJson).match(request, mockk())
506 | }
507 | }
508 |
509 | @Test
510 | @DisplayName("query is empty")
511 | fun testUnmatchedEmptyQuery() {
512 | val request = mockk()
513 | val parameters = Parameters()
514 | val json = """{ "query": "" }"""
515 |
516 | every { request.bodyAsString } returns json
517 |
518 | assertThrows {
519 | GraphqlBodyMatcher.withRequestJson(json).match(request, parameters)
520 | }
521 | }
522 |
523 | }
524 |
525 |
526 | @Nested
527 | @DisplayName("test `withRequestQueryAndVariables`")
528 | inner class WithRequestQueryAndVariables {
529 | @Test
530 | @DisplayName("test `withRequest` when queries are identical")
531 | fun testMatchedIdenticalWithRequest() {
532 | val request = mockk()
533 | val parameters = Parameters()
534 | val query = "{ hero { name friends { name }}}"
535 | // language=json
536 | val json = """
537 | {
538 | "query": "{ hero { name friends { name }}}"
539 | }
540 | """.trimIndent()
541 |
542 | every { request.bodyAsString } returns json
543 |
544 | val actual = GraphqlBodyMatcher.withRequestQueryAndVariables(query).match(request, parameters)
545 | assertTrue(actual.isExactMatch)
546 | }
547 |
548 | @Test
549 | @DisplayName("test `withRequest` when queries and variables are identical")
550 | fun testMatchedIdenticalWithRequestAndVariables() {
551 | val request = mockk()
552 | val parameters = Parameters()
553 | val query = "query GetCharacters(\$ids: [ID!]) { characters(ids: \$ids) { name age } }"
554 | val variables = """{"ids": [1, 2, 3]}"""
555 | val escaped = "\$ids"
556 |
557 | val json = """
558 | {
559 | "query": "query GetCharacters($escaped: [ID!]) { characters(ids: $escaped) { name age } }",
560 | "variables": {
561 | "ids": [
562 | 1,
563 | 2,
564 | 3
565 | ]
566 | }
567 | }
568 | """.trimIndent()
569 |
570 | every { request.bodyAsString } returns json
571 |
572 | val actual = GraphqlBodyMatcher.withRequestQueryAndVariables(query, variables).match(request, parameters)
573 | assertTrue(actual.isExactMatch)
574 | }
575 | }
576 |
577 | @Nested
578 | @DisplayName("test `withRequest`")
579 | inner class WithRequestTest {
580 | @Test
581 | @DisplayName("returns Parameters with expectedJsonKey")
582 | fun testMatchedIdentical() {
583 | // language=json
584 | val json = """
585 | {
586 | "query": "{ hero { name friends { name }}}"
587 | }
588 | """.trimIndent()
589 |
590 | val actual = GraphqlBodyMatcher.withRequest(json)
591 | assertTrue(actual.containsKey("query"))
592 | assertEquals("{ hero { name friends { name }}}", actual.getString("query"))
593 | assertFalse(actual.containsKey("variables"))
594 | assertFalse(actual.containsKey("operationName"))
595 | }
596 |
597 | @Test
598 | @DisplayName("Throws JsonException when json is empty")
599 | fun testUnmatchedEmptyJson() {
600 | val emptyJson = ""
601 |
602 | assertThrows {
603 | GraphqlBodyMatcher.withRequest(emptyJson)
604 | }
605 | }
606 |
607 | @Test
608 | @DisplayName("Throws JsonException when json is invalid")
609 | fun testUnmatchedInvalidJson() {
610 | val invalidJson = """
611 | {
612 | "query": "{ hero { name, age, height }"
613 | """.trimIndent()
614 |
615 | assertThrows {
616 | GraphqlBodyMatcher.withRequest(invalidJson)
617 | }
618 | }
619 |
620 | @Test
621 | @DisplayName("Throws InvalidSyntaxException when query is invalid")
622 | fun testUnmatchedInvalidQuery() {
623 | // language=json
624 | val invalidQueryJson = """
625 | {
626 | "query": "{ hero { name, age, height "
627 | }
628 | """.trimIndent()
629 |
630 | assertThrows {
631 | GraphqlBodyMatcher.withRequest(invalidQueryJson)
632 | }
633 | }
634 |
635 | @Test
636 | @DisplayName("Throws InvalidSyntaxException when query is empty")
637 | fun testUnmatchedEmptyQuery() {
638 | val json = """{ "query": "" }"""
639 |
640 | assertThrows {
641 | GraphqlBodyMatcher.withRequest(json)
642 | }
643 | }
644 | }
645 | }
646 |
--------------------------------------------------------------------------------
/wiremock-graphql-extension/src/test/kotlin/io/github/nilwurtz/integration/ContainerTest.kt:
--------------------------------------------------------------------------------
1 | package io.github.nilwurtz.integration
2 |
3 | import com.github.tomakehurst.wiremock.client.WireMock
4 | import io.github.nilwurtz.GraphqlBodyMatcher
5 | import org.junit.jupiter.api.Assertions.assertEquals
6 | import org.junit.jupiter.api.Assertions.assertTrue
7 | import org.junit.jupiter.api.DisplayName
8 | import org.junit.jupiter.api.Test
9 | import org.testcontainers.junit.jupiter.Container
10 | import org.testcontainers.junit.jupiter.Testcontainers
11 | import org.testcontainers.utility.DockerImageName
12 | import org.wiremock.integrations.testcontainers.WireMockContainer
13 | import java.net.http.HttpClient
14 | import java.nio.file.Paths
15 | import java.util.*
16 |
17 | @Testcontainers
18 | class ContainerTest {
19 |
20 | companion object {
21 | const val QUERY = "{ query }"
22 | const val VARIABLES = """
23 | {
24 | "abc": 123
25 | }
26 | """
27 | const val OPERATION_NAME = "operationName"
28 | }
29 |
30 | @Container
31 | val wireMockContainer: WireMockContainer =
32 | WireMockContainer(
33 | DockerImageName.parse(WireMockContainer.OFFICIAL_IMAGE_NAME).withTag("3.1.0")
34 | )
35 | .withExposedPorts(8080)
36 | .withExtensions(
37 | GraphqlBodyMatcher.extensionName,
38 | Collections.singleton("io.github.nilwurtz.GraphqlBodyMatcher"),
39 | Collections.singleton(
40 | Paths.get(
41 | "target",
42 | "test-wiremock-extension",
43 | "wiremock-graphql-extension.jar"
44 | ).toFile()
45 | )
46 | )
47 | .withMappingFromResource("mappings/all.json")
48 | .withMappingFromResource("mappings/operationName.json")
49 | .withMappingFromResource("mappings/variables.json")
50 | .withMappingFromResource("mappings/query.json")
51 |
52 | @Test
53 | fun `should start wiremock container`() {
54 | assertTrue(wireMockContainer.isRunning)
55 | }
56 |
57 | @Test
58 | fun testMatch() {
59 | WireMock(wireMockContainer.port).register(
60 | WireMock.post(WireMock.urlEqualTo("/graphql"))
61 | .andMatching(GraphqlBodyMatcher.extensionName, GraphqlBodyMatcher.withRequest("""{"query": "query { name id }"}"""))
62 | .willReturn(WireMock.ok())
63 | )
64 | val client = HttpClient.newHttpClient()
65 | val request = java.net.http.HttpRequest.newBuilder()
66 | .uri(java.net.URI.create("${wireMockContainer.baseUrl}/graphql"))
67 | .POST(java.net.http.HttpRequest.BodyPublishers.ofString("""{"query": "query { id name }"}"""))
68 | .build().let { client.send(it, java.net.http.HttpResponse.BodyHandlers.ofString()) }
69 |
70 | assertEquals(200, request.statusCode())
71 | }
72 |
73 | @Test
74 | @DisplayName("Test expected query contains new line")
75 | fun testNewLineContains() {
76 | val expectedQuery = """
77 | query DemoQuery {
78 | demo {
79 | id
80 | name
81 | }
82 | }
83 | """.trimIndent()
84 | val expectedJson = """
85 | {
86 | "query": "$expectedQuery"
87 | }
88 | """.trimIndent()
89 | WireMock(wireMockContainer.port).register(
90 | WireMock.post(WireMock.urlEqualTo("/graphql"))
91 | .andMatching(GraphqlBodyMatcher.extensionName, GraphqlBodyMatcher.withRequest(expectedJson))
92 | .willReturn(WireMock.ok())
93 | )
94 |
95 | val query = "query DemoQuery { demo { id name } }"
96 | val client = HttpClient.newHttpClient()
97 | val request = java.net.http.HttpRequest.newBuilder()
98 | .uri(java.net.URI.create("${wireMockContainer.baseUrl}/graphql"))
99 | .POST(java.net.http.HttpRequest.BodyPublishers.ofString("""{"query": "$query"}"""))
100 | .build().let { client.send(it, java.net.http.HttpResponse.BodyHandlers.ofString()) }
101 |
102 | assertEquals(200, request.statusCode())
103 | }
104 |
105 | @Test
106 | fun testMappingsAll() {
107 | val json = """
108 | {
109 | "query": "$QUERY",
110 | "variables": $VARIABLES,
111 | "operationName": "$OPERATION_NAME"
112 | }
113 | """.trimIndent()
114 | val client = HttpClient.newHttpClient()
115 | val request = java.net.http.HttpRequest.newBuilder()
116 | .uri(java.net.URI.create("${wireMockContainer.baseUrl}/graphql"))
117 | .POST(java.net.http.HttpRequest.BodyPublishers.ofString(json))
118 | .build().let { client.send(it, java.net.http.HttpResponse.BodyHandlers.ofString()) }
119 |
120 | assertEquals(200, request.statusCode())
121 | }
122 |
123 | @Test
124 | fun testMappingsOperationName() {
125 | val json = """
126 | {
127 | "query": "$QUERY",
128 | "operationName": "$OPERATION_NAME"
129 | }
130 | """.trimIndent()
131 | val client = HttpClient.newHttpClient()
132 | val request = java.net.http.HttpRequest.newBuilder()
133 | .uri(java.net.URI.create("${wireMockContainer.baseUrl}/graphql"))
134 | .POST(java.net.http.HttpRequest.BodyPublishers.ofString(json))
135 | .build().let { client.send(it, java.net.http.HttpResponse.BodyHandlers.ofString()) }
136 |
137 | assertEquals(200, request.statusCode())
138 | }
139 |
140 | @Test
141 | fun testMappingsVariables() {
142 | val json = """
143 | {
144 | "query": "$QUERY",
145 | "variables": $VARIABLES
146 | }
147 | """.trimIndent()
148 | val client = HttpClient.newHttpClient()
149 | val request = java.net.http.HttpRequest.newBuilder()
150 | .uri(java.net.URI.create("${wireMockContainer.baseUrl}/graphql"))
151 | .POST(java.net.http.HttpRequest.BodyPublishers.ofString(json))
152 | .build().let { client.send(it, java.net.http.HttpResponse.BodyHandlers.ofString()) }
153 |
154 | assertEquals(200, request.statusCode())
155 | }
156 |
157 | @Test
158 | fun testMappingsQuery() {
159 | val json = """
160 | {
161 | "query": "$QUERY"
162 | }
163 | """.trimIndent()
164 | val client = HttpClient.newHttpClient()
165 | val request = java.net.http.HttpRequest.newBuilder()
166 | .uri(java.net.URI.create("${wireMockContainer.baseUrl}/graphql"))
167 | .POST(java.net.http.HttpRequest.BodyPublishers.ofString(json))
168 | .build().let { client.send(it, java.net.http.HttpResponse.BodyHandlers.ofString()) }
169 |
170 | assertEquals(200, request.statusCode())
171 | }
172 | }
--------------------------------------------------------------------------------
/wiremock-graphql-extension/src/test/resources/mappings/all.json:
--------------------------------------------------------------------------------
1 | {
2 | "request": {
3 | "urlPathPattern": "/graphql",
4 | "method": "POST",
5 | "customMatcher": {
6 | "name": "graphql-body-matcher",
7 | "parameters": {
8 | "query": "{ query }",
9 | "variables": {
10 | "abc": 123
11 | },
12 | "operationName": "operationName"
13 | }
14 | }
15 | },
16 | "response": {
17 | "status": 200
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/wiremock-graphql-extension/src/test/resources/mappings/operationName.json:
--------------------------------------------------------------------------------
1 | {
2 | "request": {
3 | "urlPathPattern": "/graphql",
4 | "method": "POST",
5 | "customMatcher": {
6 | "name": "graphql-body-matcher",
7 | "parameters": {
8 | "query": "{ query }",
9 | "operationName": "operationName"
10 | }
11 | }
12 | },
13 | "response": {
14 | "status": 200
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/wiremock-graphql-extension/src/test/resources/mappings/query.json:
--------------------------------------------------------------------------------
1 | {
2 | "request": {
3 | "urlPathPattern": "/graphql",
4 | "method": "POST",
5 | "customMatcher": {
6 | "name": "graphql-body-matcher",
7 | "parameters": {
8 | "query": "{ query }"
9 | }
10 | }
11 | },
12 | "response": {
13 | "status": 200
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/wiremock-graphql-extension/src/test/resources/mappings/variables.json:
--------------------------------------------------------------------------------
1 | {
2 | "request": {
3 | "urlPathPattern": "/graphql",
4 | "method": "POST",
5 | "customMatcher": {
6 | "name": "graphql-body-matcher",
7 | "parameters": {
8 | "query": "{ query }",
9 | "variables": {
10 | "abc": 123
11 | }
12 | }
13 | }
14 | },
15 | "response": {
16 | "status": 200
17 | }
18 | }
19 |
--------------------------------------------------------------------------------