Skip to content

Commit

Permalink
Allow to overwrite providers when using testkit.testModule (#2219)
Browse files Browse the repository at this point in the history
  • Loading branch information
kamilkisiela committed Jun 20, 2022
1 parent 0728057 commit c0a3d55
Show file tree
Hide file tree
Showing 6 changed files with 234 additions and 2 deletions.
5 changes: 5 additions & 0 deletions .changeset/rare-apples-fly.md
@@ -0,0 +1,5 @@
---
'graphql-modules': minor
---

Allow to overwrite providers when using testkit.testModule
1 change: 1 addition & 0 deletions package.json
Expand Up @@ -44,6 +44,7 @@
"@typescript-eslint/parser": "5.28.0",
"apollo-server": "3.9.0",
"apollo-server-express": "3.9.0",
"apollo-datasource-rest": "3.6.1",
"artillery": "1.7.9",
"benchmark": "2.1.4",
"babel-plugin-parameter-decorator": "1.0.16",
Expand Down
17 changes: 17 additions & 0 deletions packages/graphql-modules/src/testing/test-module.ts
Expand Up @@ -118,6 +118,23 @@ function transformModule(mod: Module, config?: TestModuleConfig) {
});
}

if (config?.providers) {
transforms.push((m) => {
const sourceProviders =
typeof m.config.providers === 'function'
? m.config.providers()
: m.config.providers;
const overrideProviders =
typeof config.providers === 'function'
? config.providers()
: config.providers;
return moduleFactory({
...m.config,
providers: [...(sourceProviders || []), ...(overrideProviders || [])],
});
});
}

if (transforms) {
return transforms.reduce((m, transform) => transform(m), mod);
}
Expand Down
50 changes: 50 additions & 0 deletions packages/graphql-modules/tests/di-providers.spec.ts
Expand Up @@ -1348,3 +1348,53 @@ test('instantiate operation-scoped provider once per many fields', async () => {
expect(constructor).toBeCalledTimes(1);
expect(log).toBeCalledTimes(2);
});

test('Last operation-scoped provider in the list wins', async () => {
const token = new InjectionToken<string>('token');

const app = createApplication({
modules: [
createModule({
id: 'mod',
typeDefs: gql`
type Query {
token: String
}
`,
resolvers: {
Query: {
token(_: {}, __: {}, { injector }: GraphQLModules.ModuleContext) {
return injector.get(token);
},
},
},
}),
],
providers: [
{
provide: token,
useValue: 'first',
},
{
provide: token,
useValue: 'second',
},
{
provide: token,
useValue: 'last',
},
],
});

const result = await testkit.execute(app, {
contextValue: {},
document: gql`
{
token
}
`,
});

expect(result.errors).not.toBeDefined();
expect(result.data?.token).toEqual('last');
});
150 changes: 149 additions & 1 deletion packages/graphql-modules/tests/testing.spec.ts
@@ -1,6 +1,7 @@
import 'reflect-metadata';
import type { TypedDocumentNode } from '@graphql-typed-document-node/core';
import { concatAST } from 'graphql';
import { RESTDataSource } from 'apollo-datasource-rest';
import {
createApplication,
createModule,
Expand Down Expand Up @@ -105,7 +106,7 @@ describe('testModule', () => {
});
});

test('should overwrite providers in a module on demand', async () => {
test('should overwrite singleton providers in a module on demand', async () => {
@Injectable({
scope: Scope.Singleton,
})
Expand Down Expand Up @@ -139,6 +140,7 @@ describe('testModule', () => {
},
},
},
providers: [Data],
});

const app = testkit.testModule(initialModule, {
Expand Down Expand Up @@ -174,6 +176,152 @@ describe('testModule', () => {
});
});

test('should overwrite operation providers in a module on demand', async () => {
@Injectable({
scope: Scope.Operation,
})
class Data {
getById(id: string) {
return {
id,
};
}
}

const initialModule = createModule({
id: 'tested',
typeDefs: gql`
type Query {
foo(id: ID!): Foo!
}
type Foo {
id: ID
}
`,
resolvers: {
Query: {
foo(
_: {},
{ id }: { id: string },
{ injector }: GraphQLModules.ModuleContext
) {
return injector.get(Data).getById(id);
},
},
},
providers: [Data],
});

const app = testkit.testModule(initialModule, {
providers: [
{
provide: Data,
scope: Scope.Operation,
useValue: {
getById() {
return {
id: 'mocked',
};
},
},
},
],
});

const result = await testkit.execute(app, {
document: gql`
{
foo(id: "not-mocked") {
id
}
}
`,
});

expect(result.errors).not.toBeDefined();
expect(result.data).toEqual({
foo: {
id: 'mocked',
},
});
});

test('should overwrite operation-scoped classes in a module on demand', async () => {
@Injectable({
scope: Scope.Operation,
})
class Data extends RESTDataSource {
constructor() {
super();
}

getById(id: string) {
return {
id,
};
}
}

const initialModule = createModule({
id: 'tested',
typeDefs: gql`
type Query {
foo(id: ID!): Foo!
}
type Foo {
id: ID
}
`,
resolvers: {
Query: {
foo(
_: {},
{ id }: { id: string },
{ injector }: GraphQLModules.ModuleContext
) {
return injector.get(Data).getById(id);
},
},
},
providers: [Data],
});

const app = testkit.testModule(initialModule, {
providers: [
{
provide: Data,
scope: Scope.Operation,
useValue: {
getById() {
return {
id: 'mocked',
};
},
},
},
],
});

const result = await testkit.execute(app, {
document: gql`
{
foo(id: "not-mocked") {
id
}
}
`,
});

expect(result.errors).not.toBeDefined();
expect(result.data).toEqual({
foo: {
id: 'mocked',
},
});
});

test('should inherit typeDefs from other modules', () => {
const initialModule = createModule({
id: 'tested',
Expand Down
13 changes: 12 additions & 1 deletion yarn.lock
Expand Up @@ -4051,6 +4051,17 @@ anymatch@^3.0.3, anymatch@~3.1.2:
normalize-path "^3.0.0"
picomatch "^2.0.4"

apollo-datasource-rest@3.6.1:
version "3.6.1"
resolved "https://registry.yarnpkg.com/apollo-datasource-rest/-/apollo-datasource-rest-3.6.1.tgz#0975c5c8dfd1d2cbda58af268b9029451af8858e"
integrity sha512-3RMM48DKva01YrmPYpiBdtva7r9pJkgrMz7BuwAdhF2RXU9WhgOwZvUUZHqi+8ARNGRjVZA5BdCcEt8lIbYhOA==
dependencies:
"@apollo/utils.keyvaluecache" "^1.0.1"
apollo-datasource "^3.3.2"
apollo-server-env "^4.2.1"
apollo-server-errors "^3.3.1"
http-cache-semantics "^4.1.0"

apollo-datasource@^3.3.2:
version "3.3.2"
resolved "https://registry.yarnpkg.com/apollo-datasource/-/apollo-datasource-3.3.2.tgz#5711f8b38d4b7b53fb788cb4dbd4a6a526ea74c8"
Expand Down Expand Up @@ -7924,7 +7935,7 @@ htmlparser2@^3.9.1:
inherits "^2.0.1"
readable-stream "^3.1.1"

http-cache-semantics@^4.0.0:
http-cache-semantics@^4.0.0, http-cache-semantics@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz#49e91c5cbf36c9b94bcfcd71c23d5249ec74e390"
integrity sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==
Expand Down

1 comment on commit c0a3d55

@vercel
Copy link

@vercel vercel bot commented on c0a3d55 Jun 20, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.