Skip to content

Commit 77c6e6e

Browse files
Documentation and integration tests for Bun (#1746)
* Integration tests and docs for Bun * Add Bun to CI * See what's going on * Now it makes sense * Maybe? * Better error handling * Add timeout * Give another try * chore(dependencies): updated changesets for modified dependencies * Make it happy * Prettier 😄 * Do not test it in Node 14 * chore(dependencies): updated changesets for modified dependencies Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
1 parent cd0051b commit 77c6e6e

File tree

19 files changed

+298
-65
lines changed

19 files changed

+298
-65
lines changed
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
"@graphql-yoga/plugin-apollo-inline-trace": patch
3+
---
4+
5+
dependencies updates:
6+
7+
- Added dependency [`@whatwg-node/[email protected]` ↗︎](https://www.npmjs.com/package/@whatwg-node/fetch/v/0.4.3) (to `dependencies`)
8+
- Removed dependency [`@whatwg-node/fetch@^0.4.2` ↗︎](https://www.npmjs.com/package/@whatwg-node/fetch/v/null) (from `peerDependencies`)
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
"@graphql-yoga/plugin-apq": patch
3+
---
4+
5+
dependencies updates:
6+
7+
- Updated dependency [`@whatwg-node/[email protected]` ↗︎](https://www.npmjs.com/package/@whatwg-node/fetch/v/0.4.3) (from `^0.4.2`, in `dependencies`)
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
"graphql-yoga": patch
3+
---
4+
5+
dependencies updates:
6+
7+
- Updated dependency [`@whatwg-node/[email protected]` ↗︎](https://www.npmjs.com/package/@whatwg-node/fetch/v/0.4.3) (from `^0.4.2`, in `dependencies`)
8+
- Updated dependency [`@whatwg-node/[email protected]` ↗︎](https://www.npmjs.com/package/@whatwg-node/server/v/0.4.4) (from `0.4.2`, in `dependencies`)

.github/workflows/ci.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ jobs:
3535
node-version: ${{ matrix.node-version }}
3636
cache: 'yarn'
3737

38+
- name: Setup Bun Runtime
39+
uses: antongolub/action-setup-bun@v1
40+
3841
- name: Cache Node Modules
3942
uses: actions/cache@v3
4043
id: node-modules-cache-test-node
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
import { spawn } from 'child_process'
2+
import puppeteer from 'puppeteer'
3+
4+
let browser: puppeteer.Browser
5+
let page: puppeteer.Page
6+
let bunProcess: ReturnType<typeof spawn>
7+
8+
const timings = {
9+
waitForSelector: 999,
10+
waitForResponse: 1999,
11+
}
12+
13+
jest.setTimeout(20000)
14+
15+
let toSkip = false
16+
17+
describe('Bun integration', () => {
18+
let serverUrl: string
19+
beforeAll(async () => {
20+
if (process.versions.node.startsWith('14')) {
21+
toSkip = true
22+
return
23+
}
24+
// Start Bun
25+
bunProcess = spawn('yarn', ['workspace', 'example-bun', 'start'])
26+
27+
serverUrl = await new Promise((resolve, reject) => {
28+
bunProcess.stderr?.on('data', (chunk) => {
29+
const chunkString = chunk.toString('utf-8')
30+
console.error(chunk.toString('utf-8'))
31+
if (chunkString.includes('Command failed')) {
32+
reject(new Error('Bun failed to start'))
33+
}
34+
})
35+
36+
bunProcess.stdout?.on('data', (chunk) => {
37+
const chunkString = chunk.toString('utf-8')
38+
console.log(chunk.toString('utf-8'))
39+
if (chunkString.includes('Server is running on')) {
40+
resolve(chunkString.split('Server is running on ')[1])
41+
}
42+
})
43+
})
44+
45+
// Launch puppeteer
46+
browser = await puppeteer.launch({
47+
// If you wanna run tests with open browser
48+
// set your PUPPETEER_HEADLESS env to "false"
49+
headless: process.env.PUPPETEER_HEADLESS !== 'false',
50+
args: ['--incognito'],
51+
})
52+
})
53+
54+
beforeEach(async () => {
55+
if (toSkip) {
56+
return
57+
}
58+
if (page !== undefined) {
59+
await page.close()
60+
}
61+
const context = await browser.createIncognitoBrowserContext()
62+
page = await context.newPage()
63+
})
64+
65+
afterAll(async () => {
66+
if (toSkip) {
67+
return
68+
}
69+
await browser.close()
70+
bunProcess.kill()
71+
})
72+
73+
it('go to GraphiQL page', async () => {
74+
if (toSkip) {
75+
return
76+
}
77+
// Go the the right route
78+
const body = await page.goto(
79+
`${serverUrl}?query=query+Hello+%7B%0A%09greetings%0A%7D`,
80+
)
81+
82+
let strIntro = ''
83+
try {
84+
// A-1/ Wait for the introspection query result getting our type "greetings"
85+
const resIntro = await page.waitForResponse(
86+
(res) => res.url().endsWith('/graphql'),
87+
{
88+
timeout: timings.waitForResponse,
89+
},
90+
)
91+
const jsonIntro = await resIntro.json()
92+
strIntro = JSON.stringify(jsonIntro, null, 0)
93+
} catch (error) {
94+
// We had an issue grabbing the introspection query result!
95+
// let's see what is in the html with the finafinally
96+
} finally {
97+
const bodyContent = await body?.text()
98+
// B/ Check that GraphiQL is showing
99+
expect(bodyContent).toContain(`Yoga GraphiQL`)
100+
}
101+
102+
// A-2/ Finish the test after the body check
103+
expect(strIntro).toContain(`"name":"greetings"`)
104+
105+
// C/ Tigger the default request and wait for the response
106+
const [res] = await Promise.all([
107+
page.waitForResponse((res) => res.url().endsWith('/graphql'), {
108+
timeout: timings.waitForResponse,
109+
}),
110+
page.click(`button[class="execute-button"]`),
111+
])
112+
113+
const json = await res.json()
114+
const str = JSON.stringify(json, null, 0)
115+
expect(str).toContain(`{"data":{"greetings":"Hello Bun!"}}`)
116+
})
117+
})

examples/bun/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
{
22
"name": "example-bun",
33
"version": "0.0.0",
4+
"license": "MIT",
45
"scripts": {
56
"start": "bun src/index.ts",
67
"check": "exit 0"

examples/bun/src/index.ts

Lines changed: 2 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -6,38 +6,16 @@ const yoga = createYoga({
66
type Query {
77
greetings: String
88
}
9-
10-
type Subscription {
11-
time: String
12-
}
139
`,
1410
resolvers: {
1511
Query: {
16-
greetings: () => 'Hello world!',
17-
},
18-
Subscription: {
19-
time: {
20-
subscribe: () =>
21-
new Repeater(async (push, end) => {
22-
const interval = setInterval(() => {
23-
push(new Date().toISOString())
24-
}, 1000)
25-
end.then(() => clearInterval(interval))
26-
await end
27-
}),
28-
resolve: (value) => value,
29-
},
12+
greetings: () => 'Hello Bun!',
3013
},
3114
},
3215
}),
3316
})
3417

35-
const server = Bun.serve({
36-
fetch: yoga,
37-
port: 4000,
38-
hostname: '0.0.0.0',
39-
development: true,
40-
})
18+
const server = Bun.serve(yoga)
4119

4220
console.info(
4321
`Server is running on ${new URL(yoga.graphqlEndpoint, server.hostname)}`,

examples/error-handling/__integration-tests__/error-handling.spec.ts

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,25 @@ describe('error-handling example integration', () => {
2323
)
2424
const body = await response.json()
2525

26-
expect(body.errors).toBeDefined()
27-
expect(body.errors[0].message).toEqual('Unexpected error.')
28-
expect(body.data).toBeNull()
26+
expect(body).toMatchInlineSnapshot(`
27+
{
28+
"data": null,
29+
"errors": [
30+
{
31+
"locations": [
32+
{
33+
"column": 7,
34+
"line": 1,
35+
},
36+
],
37+
"message": "Unexpected error.",
38+
"path": [
39+
"greeting",
40+
],
41+
},
42+
],
43+
}
44+
`)
2945
})
3046

3147
it('should get a custom error', async () => {
@@ -34,9 +50,10 @@ describe('error-handling example integration', () => {
3450
)
3551
const body = await response.json()
3652

37-
expect(body.errors).toBeDefined()
38-
expect(body.errors).toMatchInlineSnapshot(`
39-
[
53+
expect(body).toMatchInlineSnapshot(`
54+
{
55+
"data": null,
56+
"errors": [
4057
{
4158
"extensions": {
4259
"code": "USER_NOT_FOUND",
@@ -55,7 +72,8 @@ describe('error-handling example integration', () => {
5572
"user",
5673
],
5774
},
58-
]
59-
`)
75+
],
76+
}
77+
`)
6078
})
6179
})

examples/error-handling/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
},
99
"dependencies": {
1010
"graphql-yoga": "2.13.11",
11-
"@whatwg-node/fetch": "^0.4.2",
11+
"@whatwg-node/fetch": "0.4.3",
1212
"graphql": "^16.1.0"
1313
},
1414
"devDependencies": {

examples/error-handling/src/yoga.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ export const yoga = createYoga({
3434
Query: {
3535
greeting: async () => {
3636
// This service does not exist
37-
const greeting = await fetch('http://localhost:9876/greeting').then(
37+
const greeting = await fetch('http://localhost:9999/greeting').then(
3838
(res) => res.text(),
3939
)
4040

0 commit comments

Comments
 (0)