oasisprotocol / wallet

Official non-custodial wallet for the Oasis Network.
https://wallet.oasis.io
Apache License 2.0
110 stars 46 forks source link

Mock RPC calls in tests (some tests print `connect ECONNREFUSED 127.0.0.1:42280`) #815

Open lukaw3d opened 2 years ago

lukaw3d commented 2 years ago

See https://github.com/oasisprotocol/oasis-wallet-web/runs/6108972874?check_suite_focus=true#step:6:22

By logging requests in node_modules/@oasisprotocol/client/dist/client.js, I get the following unmocked GRPC calls

class GRPCWrapper {
    callUnary(desc, request) {
        const name = desc.name;
        const method = this.base + name;
        console.log('callUnary', method);
 PASS  src/app/pages/StakingPage/Features/DelegationList/__tests__/ActiveDelegationList.test.tsx (5.401 s)

    console.log callUnary http://localhost:42280/oasis-core.Staking/Account

 PASS  src/app/components/Toolbar/__tests__/index.test.tsx

    console.log callUnary http://localhost:42280/oasis-core.Beacon/GetEpoch

 PASS  src/app/components/AddEscrowForm/__tests__/index.test.tsx

    Cannot log after tests are done. Did you forget to wait for something async in your test?
    Attempted to log "callUnary http://localhost:42280/oasis-core.Staking/Account".

 PASS  src/app/pages/OpenWalletPage/Features/FromPrivateKey/__tests__/index.test.tsx (8.583 s)

    console.log callUnary http://localhost:42280/oasis-core.Staking/Account

    console.log callUnary http://localhost:42280/oasis-core.Staking/Account

    Cannot log after tests are done. Did you forget to wait for something async in your test?
    Attempted to log "callUnary http://localhost:42280/oasis-core.Staking/Account".

 PASS  src/app/pages/StakingPage/Features/DelegationList/__tests__/DebondingDelegationList.test.tsx (9.478 s)

    console.log callUnary http://localhost:42280/oasis-core.Staking/Account

 PASS  src/app/pages/StakingPage/Features/CommissionBounds/__tests__/index.test.tsx

    console.log callUnary http://localhost:42280/oasis-core.Beacon/GetEpoch

    console.log callUnary http://localhost:42280/oasis-core.Beacon/GetEpoch
buberdds commented 2 years ago

We can provide a fake implementation of XMLHttpRequest via:

1) 3rd party lib, sample: https://github.com/oasisprotocol/oasis-wallet-web/commit/72894bc1df6d8fd19ddff7e2eef5e8c07db90089

2) Dummy mock https://github.com/oasisprotocol/oasis-wallet-web/commit/0690b0cb8711f83c7d88b161bd7a55fd0b3d3ae1

Both can be applied per test or globally via setupTests.ts

3) Write isolated/unit tests not integration tests, but that would require writing additional tests to cover actions and reducers. https://github.com/oasisprotocol/oasis-wallet-web/commit/8676dba280059b965dd7c94da399153a67632263

pro-wh commented 2 years ago

grpc-web also allows you to pass in a replacement for their "xhrIo" object when creating a grpc client. we can expose this in the typescript oasis sdk if you want

google has a mock for xhrIo: https://google.github.io/closure-library/api/goog.testing.net.XhrIo.html https://github.com/google/closure-library/blob/master/closure/goog/testing/net/xhrio.js#L37

lukaw3d commented 2 years ago

Mocking at request level for gRPC isn't pretty, e.g. AAAAABKhZGRhdGFLoWhiYWxhbmNlc6A=gAAAAB5ncnBjLXN0YXR1czowDQpncnBjLW1lc3NhZ2U6DQo=

But maybe we only need a few encoded responses like that :shrug:

We currently sometimes:

I'd rather have a NodeInternal that prints unmocked requests and is easy to mock specific methods. I got this to work:

/* setupTests.ts */
beforeEach(() => {
  // @ts-expect-error Protected property
  jest.spyOn(NodeInternal.prototype, 'callUnary')
  jest.mocked(NodeInternal.prototype['callUnary']).mockImplementation(async (desc, request) => {
    console.warn(
      'Unmocked gRPC',
      desc.getName(),
      request,
      "Mock it with e.g. jest.spyOn(NodeInternal.prototype, 'stakingAccount').mockResolvedValue()",
    )
  })
})
pro-wh commented 2 years ago

mocking the NodeInternal object or the callUnary should be fine. we have end to end tests in oasis-sdk to keep an eye on the grpc client layer