: 'babel-jest',\n '^.+\\\\.ts?
: 'babel-jest',\n '^.+\\\\.js
: 'babel-jest',\n },\n};\n","id":"95d7561c-4d50-498a-9689-2eba999ff334","is_binary":false,"title":"jest.config.js","sha":null,"inserted_at":"2024-08-23T23:25:28","updated_at":"2024-08-23T23:25:28","upload_id":null,"shortid":"HGNwQ6IR3S","source_id":"9445ca40-94ac-4a04-850c-ab4a03c753c8","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.25.2\",\n \"@babel\u002Fplugin-proposal-class-properties\": \"7.18.6\",\n \"@babel\u002Fpreset-env\": \"7.25.4\",\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":"72d4b2b6-a175-438d-9266-8b9d437bcd6a","is_binary":false,"title":"package.json","sha":null,"inserted_at":"2024-08-23T23:25:28","updated_at":"2024-08-23T23:25:28","upload_id":null,"shortid":"_M58e7j0lc","source_id":"9445ca40-94ac-4a04-850c-ab4a03c753c8","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":"4af7dc64-e14e-4ab6-9b3f-39b2ffd374c7","is_binary":false,"title":"config.json","sha":null,"inserted_at":"2024-08-23T23:25:28","updated_at":"2024-08-23T23:25:28","upload_id":null,"shortid":"PvNqrF56qM","source_id":"9445ca40-94ac-4a04-850c-ab4a03c753c8","directory_shortid":"uCkkHSF9i"},{"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":"0d9f4f06-30c7-4cce-b71b-4cb41c85f714","is_binary":false,"title":"index.ts","sha":null,"inserted_at":"2024-08-23T23:25:28","updated_at":"2024-08-23T23:25:28","upload_id":null,"shortid":"AC-h_VqW7Z","source_id":"9445ca40-94ac-4a04-850c-ab4a03c753c8","directory_shortid":"uCkkHSF9i"},{"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":"c5b4326c-36fc-4652-9782-c638b00b75d6","is_binary":false,"title":"products.graphql","sha":null,"inserted_at":"2024-08-23T23:25:28","updated_at":"2024-08-23T23:25:28","upload_id":null,"shortid":"J1fczNpxRD","source_id":"9445ca40-94ac-4a04-850c-ab4a03c753c8","directory_shortid":"aeX-X2_OX_"},{"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":"9070b95f-dad9-40bc-8cce-5f1264e6e811","is_binary":false,"title":"reviews.graphql","sha":null,"inserted_at":"2024-08-23T23:25:28","updated_at":"2024-08-23T23:25:28","upload_id":null,"shortid":"hL01bvobSE","source_id":"9445ca40-94ac-4a04-850c-ab4a03c753c8","directory_shortid":"aeX-X2_OX_"},{"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":"f1eca799-5e37-462e-a2fe-c26839ec9a51","is_binary":false,"title":"users.graphql","sha":null,"inserted_at":"2024-08-23T23:25:28","updated_at":"2024-08-23T23:25:28","upload_id":null,"shortid":"mpSlM31_Sv","source_id":"9445ca40-94ac-4a04-850c-ab4a03c753c8","directory_shortid":"aeX-X2_OX_"},{"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":"095a329c-8ea5-4d55-ad2f-d54d4a98a528","is_binary":false,"title":"schema_builder.ts","sha":null,"inserted_at":"2024-08-23T23:25:28","updated_at":"2024-08-23T23:25:28","upload_id":null,"shortid":"w6BQC1rgSc","source_id":"9445ca40-94ac-4a04-850c-ab4a03c753c8","directory_shortid":"uCkkHSF9i"},{"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":"987def37-932e-4276-a705-4375ccf8796e","is_binary":false,"title":"gateway.test.ts","sha":null,"inserted_at":"2024-08-23T23:25:28","updated_at":"2024-08-23T23:25:28","upload_id":null,"shortid":"6HtU1uj-5_","source_id":"9445ca40-94ac-4a04-850c-ab4a03c753c8","directory_shortid":"lM6RkHNaXQ"},{"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":"462ec6cb-b0bc-4aa3-9412-15075fbd8ecb","is_binary":false,"title":"products.ts","sha":null,"inserted_at":"2024-08-23T23:25:28","updated_at":"2024-08-23T23:25:28","upload_id":null,"shortid":"QK9unSpDMv","source_id":"9445ca40-94ac-4a04-850c-ab4a03c753c8","directory_shortid":"p5bqioqNxJ"},{"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":"60f911ab-db29-4b90-aeff-1aabcaa603bd","is_binary":false,"title":"reviews.ts","sha":null,"inserted_at":"2024-08-23T23:25:28","updated_at":"2024-08-23T23:25:28","upload_id":null,"shortid":"Zk-ljmh2PsQ","source_id":"9445ca40-94ac-4a04-850c-ab4a03c753c8","directory_shortid":"p5bqioqNxJ"},{"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":"b0119c70-ffb6-4145-9233-6151a99f0369","is_binary":false,"title":"users.ts","sha":null,"inserted_at":"2024-08-23T23:25:28","updated_at":"2024-08-23T23:25:28","upload_id":null,"shortid":"XqTJlTP-Yvy","source_id":"9445ca40-94ac-4a04-850c-ab4a03c753c8","directory_shortid":"p5bqioqNxJ"},{"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":"99e0ed3d-8121-4dfa-85a8-6f4de0e2149c","is_binary":false,"title":"test_helper.ts","sha":null,"inserted_at":"2024-08-23T23:25:28","updated_at":"2024-08-23T23:25:28","upload_id":null,"shortid":"63GpDL6AEas","source_id":"9445ca40-94ac-4a04-850c-ab4a03c753c8","directory_shortid":"lM6RkHNaXQ"},{"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":"a6e74b34-b4f8-45dd-9c90-fadbb3b21f68","is_binary":false,"title":"tsconfig.json","sha":null,"inserted_at":"2024-08-23T23:25:28","updated_at":"2024-08-23T23:25:28","upload_id":null,"shortid":"jZA1tne8QrV","source_id":"9445ca40-94ac-4a04-850c-ab4a03c753c8","directory_shortid":null}],"feature_flags":{"comments":false,"container_lsp":false},"updated_at":"2024-08-23T23:25:28","id":"sbo9sj","forked_template_sandbox":null,"team":null,"is_sse":false,"npm_registries":[],"forked_from_sandbox":null,"is_frozen":false,"fork_count":0,"ai_consent":false,"like_count":0,"template":"create-react-app","settings":{"ai_consent":null},"privacy":0,"source_id":"9445ca40-94ac-4a04-850c-ab4a03c753c8","forked_template":null,"restrictions":{"free_plan_editing_restricted":false,"live_sessions_restricted":false},"draft":true};