cloudflare / miniflare

🔥 Fully-local simulator for Cloudflare Workers. For the latest version, see https://github.com/cloudflare/workers-sdk/tree/main/packages/miniflare.
https://miniflare.dev
MIT License
3.77k stars 203 forks source link

Service binding not work in miniflare 3 #625

Open madawei2699 opened 1 year ago

madawei2699 commented 1 year ago

Hi,

I can't setup the service binding with miniflare 3, here is my test code:

import { Miniflare } from "miniflare";

const mf = new Miniflare({
  host: "0.0.0.0",
  port: 8787,
    workers: [
        {
            name: "my-invest-gateway",
            serviceBindings: {
                AUTH: 'my-invest-auth',
                async CHAT(request) {
          // `request` is the incoming `Request` object.
          return new Response('');
        },
            },
            scriptPath: './index.ts',
        },
        {
            name: "my-invest-auth",
            script: `
                addEventListener('fetch', event => {
                    event.respondWith(new Response('Hello world'));
                });
            `,
        },
    ],
});

afterAll(() => {
    mf.dispose();
});

describe('Chat', () => {
    test('GET /chat', async () => {
        const res = await mf.dispatchFetch('http://127.0.0.1:8787/chat/hello/jack')
        expect(res.status).toBe(200)
        const body = await res.text()
        expect(body).toEqual('Hello, world!')
    })
})

and here is my code:

import { Context, Hono } from 'hono'
import { logger } from 'hono/logger'

type Bindings = {
  AUTH: Fetcher;
  CHAT: Fetcher;
}

const app = new Hono<{ Bindings: Bindings }>()
app.use('*', logger())

// API routes

const chat = new Hono()

chat.get('/hello/:user', async (c: Context) => {
    console.log(JSON.stringify(c.env));
    // TODO: check if the user exists
    const authResponse = await c.env.AUTH.fetch(c.req.raw.clone());
    const authBody = await authResponse.json();
    console.log(`authResponse: ${JSON.stringify(authBody)}`);
    if (authResponse.status !== 200) {
        return authResponse;
    }
  return await c.env.CHAT.fetch(c.req.raw, {
        headers: {
      'X-Auth-Header': 'abcd',
      'X-User-Agent': 'gateway',
    },
    });
});

app.route('/chat', chat)

export default app

when I run npm run test, there is an error:

 MiniflareCoreError [ERR_SERVICE_NOT_MOUNTED]: Service "my-invest-auth" for binding "AUTH" not found.
    Make sure "my-invest-auth" is mounted so Miniflare knows where to find it.
mrbbot commented 1 year ago

Hey! 👋 ERR_SERVICE_NOT_MOUNTED will only be thrown by Miniflare 2. Could you double check the version of Miniflare you've got installed? It's possible multiple versions are installed and the wrong one is being picked up? Running npm why miniflare may help here.


Unrelated, but you'll also want to import Response from miniflare in your test to make sure you're using the right implementation:

import { Miniflare, Response } from "miniflare";
madawei2699 commented 1 year ago

Hi @mrbbot Thanks, but the version is 3.2.

image
mrbbot commented 1 year ago

Hmmm, very strange. A few other things to try:

madawei2699 commented 1 year ago

Hi, @mrbbot Thanks!

package.json file:

{
    "name": "my-invest-gateway",
    "version": "0.0.1",
    "private": true,
    "main": "src/index.ts",
    "scripts": {
        "deploy": "wrangler deploy src/index.ts",
        "dev": "wrangler dev src/index.ts --local",
        "test": "jest"
    },
    "dependencies": {
        "@cfworker/uuid": "^1.12.4",
        "hono": "^3.1.5"
    },
    "devDependencies": {
        "@cloudflare/workers-types": "^4.20230518.0 ",
        "@types/jest": "^29.5.2",
        "esbuild": "^0.15.1",
        "esbuild-jest": "^0.5.0",
        "jest": "^29.1.2",
        "jest-environment-miniflare": "^2.6.0",
        "miniflare": "^3.20230628.0",
        "wrangler": "^3.0.0"
    }
}

jest.config.js

module.exports = {
  transform: {
    '^.+\\.(ts|tsx)$': 'esbuild-jest',
  },
  testEnvironment: 'miniflare',
}

node REPL:

Welcome to Node.js v18.15.0.
Type ".help" for more information.
> require.resolve("miniflare")
'~/myInvestGateway/node_modules/miniflare/dist/src/index.js'
> 
mrbbot commented 1 year ago

Ah, when using Miniflare's API for testing (new Miniflare(...)), you shouldn't set testEnvironment: 'miniflare' in your Jest config. This runs your tests inside a workers environment, rather than the Node.js environment Miniflare expects. Removing testEnvironment: 'miniflare' from your config should fix the issue.

madawei2699 commented 1 year ago

Thanks @mrbbot But it still can't test 😢

> my-invest-gateway@0.0.1 test
> jest

  console.error
    service core:user:my-invest-gateway: Uncaught SyntaxError: Cannot use import statement outside a module

      at Interface.<anonymous> (node_modules/miniflare/src/runtime/index.ts:58:39)

  console.error
      at core:user:my-invest-gateway:1

      at Interface.<anonymous> (node_modules/miniflare/src/runtime/index.ts:58:39)

 FAIL  src/index.test.ts
  Chat
    ✕ GET /chat (154 ms)

  ● Chat › GET /chat

    MiniflareCoreError [ERR_RUNTIME_FAILURE]: The Workers runtime failed to start. There is likely additional logging output above.

      29 | afterAll(() => {
      30 |      mf.dispose();
    > 31 | });
         |              ^
      32 |
      33 | describe('Chat', () => {
      34 |      test('GET /chat', async () => {

      at Miniflare.#assembleAndUpdateConfig (node_modules/miniflare/src/index.ts:853:13)
      at Miniflare.#init (node_modules/miniflare/src/index.ts:537:5)
      at Mutex.runWith (node_modules/miniflare/src/shared/sync.ts:63:48)
      at Miniflare.#waitForReady (node_modules/miniflare/src/index.ts:880:5)
      at Miniflare.dispatchFetch (node_modules/miniflare/src/index.ts:928:5)
      at Object.<anonymous> (src/index.test.ts:31:17)

Test Suites: 1 failed, 1 total
Tests:       1 failed, 1 total
Snapshots:   0 total
Time:        0.548 s, estimated 1 s
Ran all test suites.
node:internal/process/promises:288
            triggerUncaughtException(err, true /* fromPromise */);
            ^

MiniflareCoreError [ERR_RUNTIME_FAILURE]: The Workers runtime failed to start. There is likely additional logging output above.

Even I add "type": "module" to package.json file and rename the jest.config.js to jest.config.cjs, the same error.

AbdallahAbis commented 1 year ago

Same issue! Screenshot 2023-07-24 at 13 33 56 Screenshot 2023-07-24 at 13 34 15

if I remove testEnvironment: "miniflare", I lose the miniflare methodes such as getMiniflareFetchMock

mrbbot commented 11 months ago

@madawei2699 apologies for not following up here! This got completely buried in my inbox. 😢 If you're still working on this project, you'll need to build your TypeScript source code first, then point Miniflare to the built output. npx wrangler build should do this for you. Replace scriptPath: "src/index.ts" with scriptPath: "dist/index.js", modules: true (assuming wrangler build produces a file called dist/index.js)

@AbdallahAbis if this is still an issue for you, would you be able to create a new GitHub issue?

daliborgogic commented 1 day ago

Similar issue with service binding #782