: 'babel-jest',\n '^.+\\\\.ts?
: 'babel-jest',\n '^.+\\\\.js
: 'babel-jest',\n },\n};\n","id":"9bc5eeec-6918-44e7-962b-ff7b3c1e856c","is_binary":false,"title":"jest.config.js","sha":null,"inserted_at":"2024-07-27T00:52:47","updated_at":"2024-07-27T00:52:47","upload_id":null,"shortid":"APqZzKNlc5T","source_id":"d19f164f-04f2-43e2-a64d-b30da6cdd878","directory_shortid":null},{"code":"{\n \"name\": \"continuous-integration-testing\",\n \"version\": \"0.0.0\",\n \"license\": \"MIT\",\n \"main\": \"index.js\",\n \"scripts\": {\n \"start\": \"ts-node-dev src\u002Findex.ts\",\n \"test\": \"jest test\"\n },\n \"dependencies\": {\n \"@graphql-tools\u002Fdelegate\": \"^10.0.0\",\n \"@graphql-tools\u002Fexecutor-http\": \"^1.0.0\",\n \"@graphql-tools\u002Fstitch\": \"^9.0.0\",\n \"@graphql-tools\u002Fstitching-directives\": \"^3.0.0\",\n \"graphql\": \"^16.6.0\",\n \"graphql-yoga\": \"^5.0.0\"\n },\n \"devDependencies\": {\n \"@babel\u002Fcore\": \"7.24.9\",\n \"@babel\u002Fplugin-proposal-class-properties\": \"7.18.6\",\n \"@babel\u002Fpreset-env\": \"7.25.0\",\n \"@babel\u002Fpreset-typescript\": \"7.24.7\",\n \"@graphql-tools\u002Fmock\": \"^9.0.0\",\n \"@graphql-tools\u002Futils\": \"^10.0.0\",\n \"@types\u002Fjest\": \"^29.2.6\",\n \"@types\u002Fnode\": \"^20.0.0\",\n \"jest\": \"^29.0.0\",\n \"typescript\": \"5.5.4\"\n }\n}\n","id":"ad4b8df0-9bcb-4fd7-8810-6437a1469d6d","is_binary":false,"title":"package.json","sha":null,"inserted_at":"2024-07-27T00:52:47","updated_at":"2024-07-27T00:52:47","upload_id":null,"shortid":"3ma03H1s119","source_id":"d19f164f-04f2-43e2-a64d-b30da6cdd878","directory_shortid":null},{"code":"{\n \"services\": {\n \"products\": {\n \"url\": \"http:\u002F\u002Flocalhost:4001\u002Fgraphql\"\n },\n \"reviews\": {\n \"url\": \"http:\u002F\u002Flocalhost:4002\u002Fgraphql\"\n },\n \"users\": {\n \"url\": \"http:\u002F\u002Flocalhost:4003\u002Fgraphql\"\n }\n }\n}\n","id":"74a91d36-106c-49da-bb5d-d84e4c59ed3c","is_binary":false,"title":"config.json","sha":null,"inserted_at":"2024-07-27T00:52:47","updated_at":"2024-07-27T00:52:47","upload_id":null,"shortid":"McuUn4wYEt8","source_id":"d19f164f-04f2-43e2-a64d-b30da6cdd878","directory_shortid":"9RD8hIMg38R"},{"code":"import { createServer } from 'node:http';\nimport { createYoga } from 'graphql-yoga';\nimport { buildGatewaySchema, buildSubschemaConfigs } from '.\u002Fschema_builder';\n\nconst schema = buildGatewaySchema(buildSubschemaConfigs());\n\nconst server = createServer(createYoga({ schema }));\n\nserver.listen(4000, () =\u003E console.log('gateway running at http:\u002F\u002Flocalhost:4000\u002Fgraphql'));\n","id":"2e987024-8ae4-4d8d-b2b1-d747e287f406","is_binary":false,"title":"index.ts","sha":null,"inserted_at":"2024-07-27T00:52:47","updated_at":"2024-07-27T00:52:47","upload_id":null,"shortid":"9r8k2BW_neM","source_id":"d19f164f-04f2-43e2-a64d-b30da6cdd878","directory_shortid":"9RD8hIMg38R"},{"code":"directive @key(selectionSet: String!) on OBJECT\ndirective @merge(\n keyField: String\n keyArg: String\n additionalArgs: String\n key: [String!]\n argsExpr: String\n) on FIELD_DEFINITION\ndirective @computed(selectionSet: String!) on FIELD_DEFINITION\n\ntype Product {\n upc: ID!\n name: String!\n price: Int!\n weight: Int!\n}\n\ntype Query {\n products(upcs: [ID!]!): [Product]! @merge(keyField: \"upc\")\n _sdl: String!\n}\n","id":"5c547115-274d-4d2e-b9fe-0a99e52b1a6b","is_binary":false,"title":"products.graphql","sha":null,"inserted_at":"2024-07-27T00:52:47","updated_at":"2024-07-27T00:52:47","upload_id":null,"shortid":"8mIXPaRV9sl","source_id":"d19f164f-04f2-43e2-a64d-b30da6cdd878","directory_shortid":"Q9gSl0BjTaO"},{"code":"directive @key(selectionSet: String!) on OBJECT\ndirective @merge(\n keyField: String\n keyArg: String\n additionalArgs: String\n key: [String!]\n argsExpr: String\n) on FIELD_DEFINITION\ndirective @computed(selectionSet: String!) on FIELD_DEFINITION\n\ntype Review {\n id: ID!\n body: String\n author: User\n product: Product\n}\n\ntype User {\n id: ID!\n totalReviews: Int!\n reviews: [Review]\n}\n\ntype Product {\n upc: ID!\n reviews: [Review]\n}\n\ntype Query {\n review(id: ID!): Review\n _users(ids: [ID!]!): [User]! @merge(keyField: \"id\")\n _products(upcs: [ID!]!): [Product]! @merge(keyField: \"upc\")\n _sdl: String!\n}\n","id":"fd9ea3d2-7cd9-4291-ad0c-de9b429e03b1","is_binary":false,"title":"reviews.graphql","sha":null,"inserted_at":"2024-07-27T00:52:47","updated_at":"2024-07-27T00:52:47","upload_id":null,"shortid":"lEe2rX9AE4z","source_id":"d19f164f-04f2-43e2-a64d-b30da6cdd878","directory_shortid":"Q9gSl0BjTaO"},{"code":"directive @key(selectionSet: String!) on OBJECT\ndirective @merge(\n keyField: String\n keyArg: String\n additionalArgs: String\n key: [String!]\n argsExpr: String\n) on FIELD_DEFINITION\ndirective @computed(selectionSet: String!) on FIELD_DEFINITION\n\ntype User {\n id: ID!\n name: String!\n username: String!\n}\n\ntype Query {\n user(id: ID!): User @merge(keyField: \"id\")\n _sdl: String!\n}\n","id":"d7321f4d-5f54-4e85-b79b-4fd0cba24428","is_binary":false,"title":"users.graphql","sha":null,"inserted_at":"2024-07-27T00:52:47","updated_at":"2024-07-27T00:52:47","upload_id":null,"shortid":"r9-m0afin89","source_id":"d19f164f-04f2-43e2-a64d-b30da6cdd878","directory_shortid":"Q9gSl0BjTaO"},{"code":"import { readFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { buildSchema } from 'graphql';\nimport { SubschemaConfig } from '@graphql-tools\u002Fdelegate';\nimport { buildHTTPExecutor } from '@graphql-tools\u002Fexecutor-http';\nimport { stitchSchemas } from '@graphql-tools\u002Fstitch';\nimport { stitchingDirectives } from '@graphql-tools\u002Fstitching-directives';\nimport config from '.\u002Fconfig.json';\n\nexport function buildSubschemaConfigs(): Record\u003Cstring, SubschemaConfig\u003E {\n return Object.entries(config.services).reduce((memo, [name, settings]) =\u003E {\n const sdl = readFileSync(join(__dirname, `.\u002Fremote_schemas\u002F${name}.graphql`), 'utf-8');\n memo[name] = {\n schema: buildSchema(sdl),\n executor: buildHTTPExecutor({ endpoint: settings.url }),\n batch: true,\n };\n return memo;\n }, {});\n}\n\nexport function buildGatewaySchema(subschemasByName: Record\u003Cstring, SubschemaConfig\u003E) {\n const { stitchingDirectivesTransformer } = stitchingDirectives();\n\n return stitchSchemas({\n subschemaConfigTransforms: [stitchingDirectivesTransformer],\n subschemas: Object.values(subschemasByName),\n });\n}\n","id":"bbf02eab-80fb-4340-92ae-fce35dab3eb8","is_binary":false,"title":"schema_builder.ts","sha":null,"inserted_at":"2024-07-27T00:52:47","updated_at":"2024-07-27T00:52:47","upload_id":null,"shortid":"608cjh4rHeQ","source_id":"d19f164f-04f2-43e2-a64d-b30da6cdd878","directory_shortid":"9RD8hIMg38R"},{"code":"import { queryMockedGateway } from '.\u002Ftest_helper';\n\ndescribe('gateway schema', () =\u003E {\n const USER_QUERY = \u002F* GraphQL *\u002F `\n {\n user(id: \"1\") {\n # id \u003C\u003C must work without this selected\n name\n username\n reviews {\n # id \u003C\u003C must work without this selected\n body\n product {\n # upc \u003C\u003C must work without this selected\n name\n price\n weight\n }\n }\n }\n }\n `;\n\n test('resolves users -\u003E reviews -\u003E products', async () =\u003E {\n const { data } = await queryMockedGateway(USER_QUERY);\n\n expect(data).toEqual({\n user: {\n name: 'users-value',\n username: 'hansolo',\n reviews: [\n {\n body: 'great',\n product: {\n name: 'gizmo',\n price: 23,\n weight: 23,\n },\n },\n ],\n },\n });\n });\n\n const REVIEW_QUERY = \u002F* GraphQL *\u002F `\n {\n review(id: \"1\") {\n # id \u003C\u003C must work without this selected\n body\n author {\n # id \u003C\u003C must work without this selected\n name\n username\n }\n product {\n # upc \u003C\u003C must work without this selected\n name\n price\n weight\n }\n }\n }\n `;\n\n test('resolves review -\u003E author + product', async () =\u003E {\n const { data } = await queryMockedGateway(REVIEW_QUERY);\n\n expect(data).toEqual({\n review: {\n body: 'great',\n author: {\n name: 'users-value',\n username: 'hansolo',\n },\n product: {\n name: 'gizmo',\n price: 23,\n weight: 23,\n },\n },\n });\n });\n\n const PRODUCTS_QUERY = \u002F* GraphQL *\u002F `\n {\n products(upcs: [\"2\"]) {\n # upc \u003C\u003C must work without this selected\n name\n price\n weight\n reviews {\n # id \u003C\u003C must work without this selected\n body\n author {\n # id \u003C\u003C must work without this selected\n name\n username\n }\n }\n }\n }\n `;\n\n test('resolves products -\u003E reviews -\u003E user', async () =\u003E {\n const { data } = await queryMockedGateway(PRODUCTS_QUERY);\n\n expect(data).toEqual({\n products: [\n {\n name: 'widget',\n price: 23,\n weight: 23,\n reviews: [\n {\n body: 'awful',\n author: {\n name: 'users-value',\n username: 'yoda',\n },\n },\n ],\n },\n ],\n });\n });\n});\n","id":"cc641965-4e0e-4a88-a68b-eece71a52f40","is_binary":false,"title":"gateway.test.ts","sha":null,"inserted_at":"2024-07-27T00:52:47","updated_at":"2024-07-27T00:52:47","upload_id":null,"shortid":"daa4bjtJKB4","source_id":"d19f164f-04f2-43e2-a64d-b30da6cdd878","directory_shortid":"R9dFEfMbEbp"},{"code":"const products = [\n { upc: '1', name: 'gizmo' },\n { upc: '2', name: 'widget' },\n];\n\nexport const resolvers = {\n Query: {\n products: (_, { upcs }) =\u003E upcs.map(upc =\u003E products.find(p =\u003E p.upc === upc)),\n },\n};\n\nexport const mocks = {\n Int: () =\u003E 23,\n};\n","id":"2d8ee0a7-a8ff-4188-8946-6c7a1285630e","is_binary":false,"title":"products.ts","sha":null,"inserted_at":"2024-07-27T00:52:47","updated_at":"2024-07-27T00:52:47","upload_id":null,"shortid":"Qaoj1yvinyg","source_id":"d19f164f-04f2-43e2-a64d-b30da6cdd878","directory_shortid":"xLi6K341cAH"},{"code":"import { IResolvers } from '@graphql-tools\u002Futils';\n\nconst reviews = [\n { id: '1', body: 'great', author: { id: '1' }, product: { upc: '1' } },\n { id: '2', body: 'awful', author: { id: '2' }, product: { upc: '2' } },\n];\n\nexport const resolvers: IResolvers = {\n Query: {\n review: (_, { id }) =\u003E reviews.find(r =\u003E r.id === id),\n _users: (_, { ids }) =\u003E ids.map((id: string) =\u003E ({ id })),\n _products: (_, { upcs }) =\u003E upcs.map((upc: string) =\u003E ({ upc })),\n },\n Product: {\n reviews: p =\u003E reviews.filter(r =\u003E r.product.upc === p.upc),\n },\n User: {\n reviews: u =\u003E reviews.filter(r =\u003E r.author.id === u.id),\n },\n};\n","id":"e337ade9-c9ff-4ee6-9e14-f9cf25a933f2","is_binary":false,"title":"reviews.ts","sha":null,"inserted_at":"2024-07-27T00:52:47","updated_at":"2024-07-27T00:52:47","upload_id":null,"shortid":"b-6205HjmCb","source_id":"d19f164f-04f2-43e2-a64d-b30da6cdd878","directory_shortid":"xLi6K341cAH"},{"code":"const users = [\n { id: '1', username: 'hansolo' },\n { id: '2', username: 'yoda' },\n];\n\nexport const resolvers = {\n Query: {\n user: (_, { id }) =\u003E users.find(u =\u003E u.id === id),\n },\n};\n","id":"921702ac-c1c1-4109-a4fa-f249b3f09395","is_binary":false,"title":"users.ts","sha":null,"inserted_at":"2024-07-27T00:52:47","updated_at":"2024-07-27T00:52:47","upload_id":null,"shortid":"1itaIZtZcom","source_id":"d19f164f-04f2-43e2-a64d-b30da6cdd878","directory_shortid":"xLi6K341cAH"},{"code":"import { graphql } from 'graphql';\nimport { createSchema } from 'graphql-yoga';\nimport { addMocksToSchema, IMocks } from '@graphql-tools\u002Fmock';\nimport { stitchingDirectives } from '@graphql-tools\u002Fstitching-directives';\nimport { IResolvers, printSchemaWithDirectives } from '@graphql-tools\u002Futils';\nimport { buildGatewaySchema, buildSubschemaConfigs } from '..\u002Fsrc\u002Fschema_builder';\nimport * as productsFixtures from '.\u002Fmock_services\u002Fproducts';\nimport * as reviewsFixtures from '.\u002Fmock_services\u002Freviews';\nimport * as usersFixtures from '.\u002Fmock_services\u002Fusers';\n\n\u002F\u002F Setup a mapping of test fixtures by service name\n\ninterface Fixture {\n resolvers?: IResolvers;\n mocks?: IMocks;\n}\n\nconst fixturesByName: Record\u003Cstring, Fixture\u003E = {\n products: productsFixtures,\n reviews: reviewsFixtures,\n users: usersFixtures,\n};\n\n\u002F\u002F Get the actual subschemas built for the production app:\nconst subschemaConfigs = buildSubschemaConfigs();\n\n\u002F\u002F Reconfigure the subschema configurations for testing...\n\u002F\u002F makes all subschemas locally-executable,\n\u002F\u002F and sets them up with mocked fixture data to test with.\nObject.entries(subschemaConfigs).forEach(([name, subschemaConfig]) =\u003E {\n const fixtures = fixturesByName[name] || {};\n\n const { stitchingDirectivesValidator } = stitchingDirectives();\n\n \u002F\u002F build all of the base schemas into locally-executable test schemas\n \u002F\u002F apply mock service resolvers to give them some simple record fixtures\n const schema = stitchingDirectivesValidator(\n createSchema({\n typeDefs: printSchemaWithDirectives(subschemaConfig.schema),\n resolvers: fixtures.resolvers,\n }),\n );\n\n \u002F\u002F apply mocks to fill in missing values\n \u002F\u002F anything without a resolver or fixture data\n \u002F\u002F gets filled in with a predictable service-specific scalar\n subschemaConfig.schema = addMocksToSchema({\n preserveResolvers: true,\n schema,\n mocks: {\n String: () =\u003E `${name}-value`,\n ...(fixtures.mocks || {}),\n },\n });\n\n \u002F\u002F remove all executors (run everything as a locally-executable schema)\n delete subschemaConfig.executor;\n});\n\n\u002F\u002F Run the gateway builder using the mocked subservices\n\u002F\u002F this gives the complete stitched gateway talking to mocked services.\nconst mockedGateway = buildGatewaySchema(subschemaConfigs);\n\nexport function queryMockedGateway(query: string, variables: any = {}) {\n return graphql({\n schema: mockedGateway,\n source: query,\n variableValues: variables,\n });\n}\n","id":"a02d9bf3-e543-4fb4-a685-313e1cfb26d7","is_binary":false,"title":"test_helper.ts","sha":null,"inserted_at":"2024-07-27T00:52:47","updated_at":"2024-07-27T00:52:47","upload_id":null,"shortid":"oc-P6ouy9iM","source_id":"d19f164f-04f2-43e2-a64d-b30da6cdd878","directory_shortid":"R9dFEfMbEbp"},{"code":"{\n \"compilerOptions\": {\n \"target\": \"esnext\",\n \"moduleResolution\": \"node\",\n \"module\": \"commonjs\",\n \"sourceMap\": true,\n \"allowSyntheticDefaultImports\": true,\n \"esModuleInterop\": true,\n \"lib\": [\"esnext\", \"DOM\"],\n \"skipLibCheck\": true,\n \"resolveJsonModule\": true\n }\n}\n","id":"de818087-4575-47c0-999a-0ed981a85e2d","is_binary":false,"title":"tsconfig.json","sha":null,"inserted_at":"2024-07-27T00:52:47","updated_at":"2024-07-27T00:52:47","upload_id":null,"shortid":"Nfdl2XdHPWZ","source_id":"d19f164f-04f2-43e2-a64d-b30da6cdd878","directory_shortid":null}],"base_git":null,"settings":{"ai_consent":null},"title":"continuous-integration-testing","screenshot_url":"https:\u002F\u002Fscreenshots.codesandbox.io\u002Fsbo9sj\u002F51.png","always_on":false,"authorization":"read","forked_template":null,"author":null,"version":53,"original_git":null,"original_git_commit_sha":null,"owned":false,"source_id":"d19f164f-04f2-43e2-a64d-b30da6cdd878","is_frozen":false,"preview_secret":null,"user_liked":false,"forked_from_sandbox":null,"free_plan_editing_restricted":false,"alias":"vibrant-pine-sbo9sj","entry":"index.js","template":"create-react-app","team":null,"pr_number":null,"restricted":false,"restrictions":{"free_plan_editing_restricted":false,"live_sessions_restricted":false},"npm_dependencies":{},"collection":false,"draft":true,"feature_flags":{"comments":false,"container_lsp":false},"updated_at":"2024-07-27T00:52:47","id":"sbo9sj","fork_count":0,"like_count":0,"tags":[],"directories":[{"id":"8d0e9672-8dc6-4e53-bf11-a35b05e25035","title":"src","inserted_at":"2024-07-27T00:52:47","updated_at":"2024-07-27T00:52:47","shortid":"9RD8hIMg38R","source_id":"d19f164f-04f2-43e2-a64d-b30da6cdd878","directory_shortid":null},{"id":"6b7cafb2-a472-4d4b-a5ef-f22fcae24449","title":"test","inserted_at":"2024-07-27T00:52:47","updated_at":"2024-07-27T00:52:47","shortid":"R9dFEfMbEbp","source_id":"d19f164f-04f2-43e2-a64d-b30da6cdd878","directory_shortid":null},{"id":"50775858-4e82-46a9-bd65-ce48e90dcd9d","title":"remote_schemas","inserted_at":"2024-07-27T00:52:47","updated_at":"2024-07-27T00:52:47","shortid":"Q9gSl0BjTaO","source_id":"d19f164f-04f2-43e2-a64d-b30da6cdd878","directory_shortid":"9RD8hIMg38R"},{"id":"40c72446-16f6-4de3-8551-dff0019dab01","title":"mock_services","inserted_at":"2024-07-27T00:52:47","updated_at":"2024-07-27T00:52:47","shortid":"xLi6K341cAH","source_id":"d19f164f-04f2-43e2-a64d-b30da6cdd878","directory_shortid":"R9dFEfMbEbp"}],"custom_template":{"id":"619bdd8e-2a1c-4bcb-95d7-74cdd68dbce6","title":"continuous-integration-testing","color":"#61DAFB","v2":false,"url":null,"published":false,"icon_url":"github","official":false},"privacy":0,"v2":false,"is_sse":false,"room_id":null,"permissions":{"prevent_sandbox_export":false,"prevent_sandbox_leaving":false},"external_resources":[]};