Skip to content

Commit c6bc090

Browse files
authored
Test Execution Context in context of parallel GraphQL requests (#2462)
1 parent c7887bb commit c6bc090

File tree

1 file changed

+136
-0
lines changed

1 file changed

+136
-0
lines changed

packages/graphql-modules/tests/execution-context.spec.ts

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import {
88
gql,
99
InjectionToken,
1010
testkit,
11+
CONTEXT,
12+
Inject,
1113
} from '../src';
1214

1315
import {
@@ -510,3 +512,137 @@ test('accessing a singleton provider with execution context in another singleton
510512
getDependencyName: expectedName,
511513
});
512514
});
515+
516+
test('accessing a singleton provider with execution context in another singleton provider (parallel requests)', async () => {
517+
const spies = {
518+
foo: jest.fn(),
519+
bar: jest.fn(),
520+
baz: jest.fn(),
521+
};
522+
523+
const Name = new InjectionToken<Promise<string>>('name');
524+
525+
@Injectable({
526+
scope: Scope.Singleton,
527+
})
528+
class Foo {
529+
@ExecutionContext()
530+
public context!: ExecutionContext;
531+
532+
constructor() {
533+
spies.foo();
534+
}
535+
536+
async getName() {
537+
return this.context.injector.get(Name);
538+
}
539+
}
540+
541+
@Injectable({
542+
scope: Scope.Singleton,
543+
})
544+
class Bar {
545+
constructor(private foo: Foo) {
546+
spies.bar();
547+
}
548+
549+
async getName() {
550+
return this.foo.getName();
551+
}
552+
}
553+
554+
@Injectable({
555+
scope: Scope.Operation,
556+
})
557+
class Baz {
558+
constructor(
559+
@Inject(Name)
560+
private name: Promise<string>
561+
) {
562+
spies.baz();
563+
}
564+
565+
async getName() {
566+
return this.name;
567+
}
568+
}
569+
570+
const mod = createModule({
571+
id: 'mod',
572+
providers: [Foo, Bar, Baz],
573+
typeDefs: gql`
574+
type Query {
575+
getName: String
576+
getDependencyName: String
577+
getNameFromContext: String
578+
}
579+
`,
580+
resolvers: {
581+
Query: {
582+
getName: async (_a: {}, _b: {}, { injector }: GraphQLModules.Context) =>
583+
injector.get(Foo).getName(),
584+
getDependencyName: async (
585+
_a: {},
586+
_b: {},
587+
{ injector }: GraphQLModules.Context
588+
) => injector.get(Bar).getName(),
589+
getNameFromContext: async (
590+
_a: {},
591+
_b: {},
592+
{ injector }: GraphQLModules.Context
593+
) => injector.get(Baz).getName(),
594+
},
595+
},
596+
});
597+
598+
const app = createApplication({
599+
modules: [mod],
600+
providers: [
601+
{
602+
provide: Name,
603+
scope: Scope.Operation,
604+
useFactory(ctx) {
605+
return new Promise((resolve) => {
606+
setTimeout(() => {
607+
resolve(`request-${ctx.requestId}`);
608+
}, Math.random() * 200);
609+
});
610+
},
611+
deps: [CONTEXT],
612+
},
613+
],
614+
});
615+
616+
const requests = new Array({ length: 5 }).map((_, i) => i);
617+
618+
const results = await Promise.all(
619+
requests.map((i) =>
620+
testkit.execute(app, {
621+
contextValue: {
622+
requestId: i,
623+
},
624+
document: gql`
625+
{
626+
getName
627+
getDependencyName
628+
getNameFromContext
629+
}
630+
`,
631+
})
632+
)
633+
);
634+
635+
expect(spies.bar).toHaveBeenCalledTimes(results.length);
636+
expect(spies.foo).toHaveBeenCalledTimes(results.length);
637+
638+
for (let i = 0; i < results.length; i++) {
639+
const result = results[i];
640+
const expectedName = `request-${i}`;
641+
expect(result.errors).not.toBeDefined();
642+
expect(result.data).toEqual({
643+
getName: expectedName,
644+
getDependencyName: expectedName,
645+
getNameFromContext: expectedName,
646+
});
647+
}
648+
});

0 commit comments

Comments
 (0)