test: migrate server to typescript

This commit is contained in:
Guillaume Chau
2023-06-12 15:47:34 +02:00
parent f1ebe703d5
commit 97c14020a0
9 changed files with 136 additions and 45 deletions
+1 -1
View File
@@ -1,4 +1,4 @@
#!/usr/bin/env node
'use strict'
import './src/index.mjs'
import './dist/index.js'
+11 -1
View File
@@ -5,6 +5,11 @@
"bin": {
"test-server": "./bin.mjs"
},
"type": "module",
"scripts": {
"build": "tsc -d",
"prepare": "pnpm run build"
},
"dependencies": {
"@apollo/server": "^4.7.3",
"@graphql-tools/schema": "^10.0.0",
@@ -19,6 +24,11 @@
"ws": "^8.13.0"
},
"devDependencies": {
"@types/shortid": "^0.0.29"
"@types/body-parser": "^1.19.2",
"@types/cors": "^2.8.13",
"@types/express": "^4.17.17",
"@types/shortid": "^0.0.29",
"@types/ws": "^8.5.5",
"typescript": "^4.7.4"
}
}
-18
View File
@@ -1,18 +0,0 @@
export let channels = []
export function resetDatabase () {
channels = [
{
id: 'general',
label: 'General',
messages: [],
},
{
id: 'random',
label: 'Random',
messages: [],
},
]
}
resetDatabase()
+30
View File
@@ -0,0 +1,30 @@
export interface Channel {
id: string
label: string
messages: Message[]
}
export interface Message {
id: string
channel: Channel
text: string
}
export let channels: Channel[] = []
export function resetDatabase (): void {
channels = [
{
id: 'general',
label: 'General',
messages: [],
},
{
id: 'random',
label: 'Random',
messages: [],
},
]
}
resetDatabase()
@@ -6,12 +6,15 @@ import { ApolloServer } from '@apollo/server'
import { expressMiddleware } from '@apollo/server/express4'
import { WebSocketServer } from 'ws'
import { useServer } from 'graphql-ws/lib/use/ws'
import { schema } from './schema.mjs'
import { resetDatabase } from './data.mjs'
import { schema } from './schema.js'
import { resetDatabase } from './data.js'
import { simulateLatency } from './util.js'
const app = express()
app.use(cors('*'))
app.use(cors({
origin: '*',
}))
app.use(bodyParser.json())
@@ -22,9 +25,6 @@ app.get('/_reset', (req, res) => {
const server = new ApolloServer({
schema,
context: () => new Promise(resolve => {
setTimeout(() => resolve({}), 50)
}),
plugins: [
// Proper shutdown for the WebSocket server.
{
@@ -42,7 +42,12 @@ const server = new ApolloServer({
await server.start()
app.use('/graphql', expressMiddleware(server))
app.use('/graphql', expressMiddleware(server, {
context: async () => {
await simulateLatency()
return {}
},
}))
const httpServer = createServer(app)
@@ -2,8 +2,8 @@ import { makeExecutableSchema } from '@graphql-tools/schema'
import { PubSub, withFilter } from 'graphql-subscriptions'
import shortid from 'shortid'
import gql from 'graphql-tag'
import { channels } from './data.mjs'
import { simulateLatency, GraphQLErrorWithCode } from './util.mjs'
import { channels } from './data.js'
import { GraphQLErrorWithCode } from './util.js'
const pubsub = new PubSub()
@@ -51,21 +51,31 @@ type Subscription {
}
`
interface AddMessageInput {
channelId: string
text: string
}
interface UpdateMessageInput {
id: string
channelId: string
text: string
}
const resolvers = {
Query: {
hello: () => simulateLatency().then(() => 'Hello world!'),
channels: () => simulateLatency().then(() => channels),
channel: (root, { id }) => simulateLatency().then(() => channels.find(c => c.id === id)),
list: () => simulateLatency().then(() => ['a', 'b', 'c']),
good: () => simulateLatency().then(() => 'good'),
hello: () => 'Hello world!',
channels: () => channels,
channel: (root: any, { id }: { id: string }) => channels.find(c => c.id === id),
list: () => ['a', 'b', 'c'],
good: () => 'good',
bad: async () => {
await simulateLatency()
throw new Error('An error')
},
},
Mutation: {
addMessage: (root, { input }) => {
addMessage: (root: any, { input }: { input: AddMessageInput }) => {
const channel = channels.find(c => c.id === input.channelId)
if (!channel) {
throw new GraphQLErrorWithCode(`Channel ${input.channelId} not found`, 'not-found')
@@ -80,12 +90,15 @@ const resolvers = {
return message
},
updateMessage: (root, { input }) => {
updateMessage: (root: any, { input }: { input: UpdateMessageInput }) => {
const channel = channels.find(c => c.id === input.channelId)
if (!channel) {
throw new GraphQLErrorWithCode(`Channel ${input.channelId} not found`, 'not-found')
}
const message = channel.messages.find(m => m.id === input.id)
if (!message) {
throw new GraphQLErrorWithCode(`Message ${input.id} not found`, 'not-found')
}
Object.assign(message, {
text: input.text,
})
@@ -1,4 +1,4 @@
import { GraphQLError } from 'graphql'
import { GraphQLError, GraphQLErrorExtensions } from 'graphql'
const shouldSimulateLatency = process.argv.includes('--simulate-latency')
@@ -11,7 +11,7 @@ if (shouldSimulateLatency) {
}
export function simulateLatency () {
return new Promise(resolve => {
return new Promise<void>(resolve => {
if (shouldSimulateLatency) {
setTimeout(resolve, latency)
} else {
@@ -21,8 +21,8 @@ export function simulateLatency () {
}
export class GraphQLErrorWithCode extends GraphQLError {
constructor (message, code, extensions) {
super(message, {
constructor (message: string, code: string, extensions?: GraphQLErrorExtensions) {
super(message, null, null, null, null, null, {
extensions: {
code,
...extensions,
+23
View File
@@ -0,0 +1,23 @@
{
"compilerOptions": {
"target": "esnext",
"module": "esnext",
"strict": true,
"importHelpers": true,
"moduleResolution": "node",
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"sourceMap": true,
"lib": [
"esnext"
],
"outDir": "dist",
},
"include": [
"src/**/*.ts",
],
"exclude": [
"node_modules"
]
}
+32 -4
View File
@@ -279,9 +279,24 @@ importers:
specifier: ^8.13.0
version: 8.13.0
devDependencies:
'@types/body-parser':
specifier: ^1.19.2
version: 1.19.2
'@types/cors':
specifier: ^2.8.13
version: 2.8.13
'@types/express':
specifier: ^4.17.17
version: 4.17.17
'@types/shortid':
specifier: ^0.0.29
version: 0.0.29
'@types/ws':
specifier: ^8.5.5
version: 8.5.5
typescript:
specifier: ^4.7.4
version: 4.9.5
packages/vue-apollo-components:
dependencies:
@@ -2800,6 +2815,13 @@ packages:
dependencies:
'@types/connect': 3.4.35
'@types/node': 18.14.0
dev: false
/@types/body-parser@1.19.2:
resolution: {integrity: sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==}
dependencies:
'@types/connect': 3.4.35
'@types/node': 18.14.0
/@types/bonjour@3.5.10:
resolution: {integrity: sha512-p7ienRMiS41Nu2/igbJxxLDWrSZ0WxM8UQgCeO9KhoVF7cOVFkrKsiDr1EsJIla8vV3oEEjGcz11jc5yimhzZw==}
@@ -2836,6 +2858,12 @@ packages:
resolution: {integrity: sha512-C7srjHiVG3Ey1nR6d511dtDkCEjxuN9W1HWAEjGq8kpcwmNM6JJkpC0xvabM7BXTG2wDq8Eu33iH9aQKa7IvLQ==}
dev: false
/@types/cors@2.8.13:
resolution: {integrity: sha512-RG8AStHlUiV5ysZQKq97copd2UmVYw3/pRMLefISZ3S1hK104Cwm7iLQ3fTKx+lsUH2CE8FlLaYeEA2LSeqYUA==}
dependencies:
'@types/node': 18.14.0
dev: true
/@types/eslint-scope@3.7.4:
resolution: {integrity: sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==}
dependencies:
@@ -2868,7 +2896,7 @@ packages:
/@types/express@4.17.17:
resolution: {integrity: sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q==}
dependencies:
'@types/body-parser': 1.19.0
'@types/body-parser': 1.19.2
'@types/express-serve-static-core': 4.17.33
'@types/qs': 6.9.7
'@types/serve-static': 1.15.0
@@ -3069,8 +3097,8 @@ packages:
'@types/node': 18.14.0
dev: false
/@types/ws@8.5.4:
resolution: {integrity: sha512-zdQDHKUgcX/zBc4GrwsE/7dVdAD8JR4EuiAXiiUhhfyIJXXb2+PrGshFyeXWQPMmmZ2XxgaqclgpIC7eTXc1mg==}
/@types/ws@8.5.5:
resolution: {integrity: sha512-lwhs8hktwxSjf9UaZ9tG5M03PGogvFaH8gUgLNbN9HKIg0dvv6q+gkSuJ8HN4/VbyxkuLzCjlN7GquQ0gUJfIg==}
dependencies:
'@types/node': 18.14.0
dev: true
@@ -14036,7 +14064,7 @@ packages:
'@types/serve-index': 1.9.1
'@types/serve-static': 1.15.0
'@types/sockjs': 0.3.33
'@types/ws': 8.5.4
'@types/ws': 8.5.5
ansi-html-community: 0.0.8
bonjour-service: 1.1.0
chokidar: 3.5.3