Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reworked integration testing using vitest #2675

Merged
merged 3 commits into from
Jun 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 5 additions & 7 deletions .github/workflows/check-integration
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ set -euo pipefail
cd integration

date
go run ./server/server.go &
go run ./server/cmd/integration/server.go &

sleep 5
curl -s --connect-timeout 5 \
Expand All @@ -15,16 +15,14 @@ curl -s --connect-timeout 5 \
--retry-max-time 40 \
--retry-connrefused \
localhost:8080 > /dev/null
npm install -g typescript
npm link typescript
echo "### running jest integration spec"
./node_modules/.bin/jest --color
echo "### running integration spec"
npm run test


echo "### validating introspected schema"
./node_modules/.bin/graphql-codegen
npm run gen

if ! diff <(tail -n +3 schema-expected.graphql) <(tail -n +3 schema-fetched.graphql) ; then
if ! diff <(tail -n +3 src/generated/schema-expected.graphql) <(tail -n +3 src/generated/schema-fetched.graphql) ; then
echo "The expected schema has changed, you need to update schema-expected.graphql with any expected changes"
exit 1
fi
4 changes: 2 additions & 2 deletions .github/workflows/integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ jobs:
strategy:
matrix:
go: ["1.18", "1.20"]
node: [14]
node: [18]
runs-on: ubuntu-latest
timeout-minutes: 3
steps:
Expand All @@ -22,7 +22,7 @@ jobs:
with:
node-version: ${{ matrix.node }}
- run: go mod download
- run: cd integration ; npm install
- run: cd integration ; npm ci
- run: .github/workflows/check-integration

federation:
Expand Down
8 changes: 4 additions & 4 deletions api/testdata/default/graph/generated.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions api/testdata/federation2/graph/generated.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

29 changes: 13 additions & 16 deletions graphql/handler/transport/sse.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,29 +73,26 @@ func (t SSE) Do(w http.ResponseWriter, r *http.Request, exec graphql.GraphExecut
return
}

rc, OpErr := exec.CreateOperationContext(ctx, params)
if OpErr != nil {
w.WriteHeader(statusFor(OpErr))
resp := exec.DispatchError(graphql.WithOperationContext(ctx, rc), OpErr)
writeJson(w, resp)
return
}

rc, opErr := exec.CreateOperationContext(ctx, params)
ctx = graphql.WithOperationContext(ctx, rc)

w.Header().Set("Content-Type", "text/event-stream")
fmt.Fprint(w, ":\n\n")
flusher.Flush()

responses, ctx := exec.DispatchOperation(ctx, rc)

for {
response := responses(ctx)
if response == nil {
break
if opErr != nil {
resp := exec.DispatchError(ctx, opErr)
writeJsonWithSSE(w, resp)
} else {
responses, ctx := exec.DispatchOperation(ctx, rc)
for {
response := responses(ctx)
if response == nil {
break
}
writeJsonWithSSE(w, response)
flusher.Flush()
}
writeJsonWithSSE(w, response)
flusher.Flush()
}

fmt.Fprint(w, "event: complete\n\n")
Expand Down
62 changes: 39 additions & 23 deletions graphql/handler/transport/sse_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,14 @@ import (
)

func TestSSE(t *testing.T) {
initialize := func(sse transport.SSE) *testserver.TestServer {
initialize := func() *testserver.TestServer {
h := testserver.New()
h.AddTransport(sse)
h.AddTransport(transport.SSE{})
return h
}

initializeWithServer := func(sse transport.SSE) (*testserver.TestServer, *httptest.Server) {
h := initialize(sse)
initializeWithServer := func() (*testserver.TestServer, *httptest.Server) {
h := initialize()
return h, httptest.NewServer(h)
}

Expand All @@ -35,51 +35,65 @@ func TestSSE(t *testing.T) {
return req
}

createHTTPRequest := func(url string, query string) (*http.Request, error) {
createHTTPRequest := func(url string, query string) *http.Request {
req, err := http.NewRequest("POST", url, strings.NewReader(query))
assert.NoError(t, err, "Request threw error -> %s", err)
require.NoError(t, err, "Request threw error -> %s", err)
req.Header.Set("Accept", "text/event-stream")
req.Header.Set("content-type", "application/json; charset=utf-8")
return req, err
return req
}

readLine := func(br *bufio.Reader) string {
bs, err := br.ReadString('\n')
if err != nil {
t.Fatal(err)
}
require.NoError(t, err)
return bs
}

t.Run("stream failure", func(t *testing.T) {
h := initialize(transport.SSE{})
h := initialize()
req := httptest.NewRequest(http.MethodPost, "/graphql", strings.NewReader(`{"query":"subscription { name }"}`))
req.Header.Set("content-type", "application/json; charset=utf-8")
w := httptest.NewRecorder()
h.ServeHTTP(w, req)
assert.Equal(t, 400, w.Code, "Request return wrong status -> %s", w.Code)
assert.Equal(t, 400, w.Code, "Request return wrong status -> %d", w.Code)
assert.Equal(t, `{"errors":[{"message":"transport not supported"}],"data":null}`, w.Body.String())
})

t.Run("decode failure", func(t *testing.T) {
h := initialize(transport.SSE{})
h := initialize()
req := createHTTPTestRequest("notjson")
w := httptest.NewRecorder()
h.ServeHTTP(w, req)
assert.Equal(t, 400, w.Code, "Request return wrong status -> %s", w.Code)
assert.Equal(t, 400, w.Code, "Request return wrong status -> %d", w.Code)
assert.Equal(t, `{"errors":[{"message":"json request body could not be decoded: invalid character 'o' in literal null (expecting 'u') body:notjson"}],"data":null}`, w.Body.String())
})

t.Run("parse failure", func(t *testing.T) {
h := initialize(transport.SSE{})
h := initialize()
req := createHTTPTestRequest(`{"query":"subscription {{ name }"}`)
w := httptest.NewRecorder()
h.ServeHTTP(w, req)
assert.Equal(t, 422, w.Code, "Request return wrong status -> %s", w.Code)

assert.Equal(t, 200, w.Code, "Request return wrong status -> %d", w.Code)
assert.Equal(t, "keep-alive", w.Header().Get("Connection"))
assert.Equal(t, "text/event-stream", w.Header().Get("Content-Type"))

br := bufio.NewReader(w.Body)

assert.Equal(t, ":\n", readLine(br))
assert.Equal(t, "\n", readLine(br))
assert.Equal(t, "event: next\n", readLine(br))
assert.Equal(t, "data: {\"errors\":[{\"message\":\"Expected Name, found {\",\"locations\":[{\"line\":1,\"column\":15}],\"extensions\":{\"code\":\"GRAPHQL_PARSE_FAILED\"}}],\"data\":null}\n", readLine(br))
assert.Equal(t, "\n", readLine(br))
assert.Equal(t, "event: complete\n", readLine(br))
assert.Equal(t, "\n", readLine(br))

_, err := br.ReadByte()
assert.Equal(t, err, io.EOF)
})

t.Run("subscribe", func(t *testing.T) {
handler, srv := initializeWithServer(transport.SSE{})
handler, srv := initializeWithServer()
defer srv.Close()

var wg sync.WaitGroup
Expand All @@ -89,13 +103,15 @@ func TestSSE(t *testing.T) {
handler.SendNextSubscriptionMessage()
}()

Client := &http.Client{}
req, err := createHTTPRequest(srv.URL, `{"query":"subscription { name }"}`)
require.NoError(t, err, "Create request threw error -> %s", err)
res, err := Client.Do(req)
client := &http.Client{}
req := createHTTPRequest(srv.URL, `{"query":"subscription { name }"}`)
res, err := client.Do(req)
require.NoError(t, err, "Request threw error -> %s", err)
defer res.Body.Close()
assert.Equal(t, 200, res.StatusCode, "Request return wrong status -> %s", res.Status)
defer func() {
require.NoError(t, res.Body.Close())
}()

assert.Equal(t, 200, res.StatusCode, "Request return wrong status -> %d", res.Status)
assert.Equal(t, "keep-alive", res.Header.Get("Connection"))
assert.Equal(t, "text/event-stream", res.Header.Get("Content-Type"))

Expand Down
3 changes: 0 additions & 3 deletions integration/.babelrc

This file was deleted.

24 changes: 24 additions & 0 deletions integration/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

node_modules
dist
dist-ssr
*.local

# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
14 changes: 0 additions & 14 deletions integration/.graphqlconfig

This file was deleted.

2 changes: 1 addition & 1 deletion integration/readme.md → integration/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ These tests run a gqlgen server against the apollo client to test real world con

First start the go server
```bash
go run integration/server/server.go
go run server/cmd/integration/server.go
```

And in another terminal:
Expand Down
17 changes: 17 additions & 0 deletions integration/codegen.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import type { CodegenConfig } from '@graphql-codegen/cli';

const config: CodegenConfig = {
overwrite: true,
schema: process.env.VITE_SERVER_URL ?? 'http://localhost:8080/query',
documents: 'src/**/*.graphql',
generates: {
'src/generated/': {
preset: 'client-preset'
},
'src/generated/schema-fetched.graphql': {
plugins: ['schema-ast'],
},
},
};

export default config;
6 changes: 0 additions & 6 deletions integration/codegen.yml

This file was deleted.

Empty file removed integration/config.yaml
Empty file.
28 changes: 0 additions & 28 deletions integration/gqlgen.yml

This file was deleted.

7 changes: 7 additions & 0 deletions integration/graphql.config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
name: Schema
schema: src/generated/schema-expected.graphql
extensions:
endpoints:
dev:
url: http://localhost:8080/query
introspect: true
Loading