diff --git a/.eslintignore b/.eslintignore index c552bf922..74db35493 100644 --- a/.eslintignore +++ b/.eslintignore @@ -2,5 +2,6 @@ src/api/yorkie/v1/yorkie_grpc_web_pb.d.ts src/api/yorkie/v1/yorkie_pb.d.ts src/api/yorkie/v1/resources_grpc_web_pb.d.ts src/api/yorkie/v1/resources_pb.d.ts +test/vitest.d.ts dist lib diff --git a/src/api/converter.ts b/src/api/converter.ts index d416a7fc2..75ca8310f 100644 --- a/src/api/converter.ts +++ b/src/api/converter.ts @@ -783,12 +783,16 @@ function toChangePack(pack: ChangePack): PbChangePack { * `errorCodeOf` returns the error code of the given connect error. */ export function errorCodeOf(error: ConnectError): string { + // NOTE(hackerwins): Currently, we only use the first detail to represent the + // error code. const infos = error.findDetails(ErrorInfo); for (const info of infos) { - return info.metadata.code; + if (info.metadata.code) { + return info.metadata.code; + } } - return ""; + return ''; } /** diff --git a/test/integration/client_test.ts b/test/integration/client_test.ts index 2e3c8c5d6..7477f7dc4 100644 --- a/test/integration/client_test.ts +++ b/test/integration/client_test.ts @@ -1,3 +1,19 @@ +/* + * Copyright 2024 The Yorkie Authors. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + import { describe, it, assert, vi, afterEach, expect } from 'vitest'; import yorkie, { @@ -15,7 +31,8 @@ import { testRPCAddr, withTwoClientsAndDocuments, } from '@yorkie-js-sdk/test/integration/integration_helper'; -import { ConnectError, Code } from '@connectrpc/connect'; +import { ConnectError, Code as ConnectCode } from '@connectrpc/connect'; +import { Code } from '@yorkie-js-sdk/src/util/error'; describe.sequential('Client', function () { afterEach(() => { @@ -49,12 +66,22 @@ describe.sequential('Client', function () { it('Can attach/detach document', async function ({ task }) { const cli = new yorkie.Client(testRPCAddr); await cli.activate(); - - const key = toDocKey(`${task.name}-${new Date().getTime()}`); - const doc = new yorkie.Document<{ version: number }>(key); + const doc = new yorkie.Document( + toDocKey(`${task.name}-${new Date().getTime()}`), + ); await cli.attach(doc); - await expect(async () => cli.attach(doc)).rejects.toThrow('is not detached'); + expect(async () => cli.attach(doc)).rejects.toThrowErrorCode( + Code.DocumentNotDetached, + ); + + await cli.detach(doc); + expect(async () => cli.detach(doc)).rejects.toThrowErrorCode( + Code.DocumentNotAttached, + ); + + await cli.deactivate(); + await cli.deactivate(); }); it('Can handle sync', async function ({ task }) { @@ -790,7 +817,7 @@ describe.sequential('Client', function () { // 01. Simulate Unknown error. vi.stubGlobal('fetch', async () => { - throw new ConnectError('Failed to fetch', Code.Unknown); + throw new ConnectError('Failed to fetch', ConnectCode.Unknown); }); doc.update((root) => { @@ -803,7 +830,7 @@ describe.sequential('Client', function () { // 02. Simulate FailedPrecondition error. vi.stubGlobal('fetch', async () => { - throw new ConnectError('Failed to fetch', Code.FailedPrecondition); + throw new ConnectError('Failed to fetch', ConnectCode.FailedPrecondition); }); await new Promise((res) => setTimeout(res, 30)); diff --git a/test/vitest.d.ts b/test/vitest.d.ts new file mode 100644 index 000000000..16f97b455 --- /dev/null +++ b/test/vitest.d.ts @@ -0,0 +1,27 @@ +/* + * Copyright 2024 The Yorkie Authors. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { Assertion, AsymmetricMatchersContaining } from 'vitest'; +import { Code } from '@yorkie-js-sdk/src/util/error'; + +interface CustomMatchers { + toThrowErrorCode: (expected: Code) => R; +} + +declare module 'vitest' { + type Assertion = CustomMatchers; + interface AsymmetricMatchersContaining extends CustomMatchers {} +} diff --git a/test/vitest.setup.ts b/test/vitest.setup.ts new file mode 100644 index 000000000..86a6848df --- /dev/null +++ b/test/vitest.setup.ts @@ -0,0 +1,29 @@ +/* + * Copyright 2024 The Yorkie Authors. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { expect } from 'vitest'; +import { Code } from '@yorkie-js-sdk/src/util/error'; + +expect.extend({ + toThrowErrorCode(received: any, expected: Code) { + const { isNot } = this; + const pass = received?.code === expected; + return { + pass, + message: () => `${received} is${isNot ? ' not' : ''} expected`, + }; + }, +}); diff --git a/vitest.config.ts b/vitest.config.ts index 2bf9616f4..e2afb57ae 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -20,6 +20,7 @@ export default defineConfig({ benchmark: { exclude: ['**/lib/**', '**/node_modules/**'], }, + setupFiles: ['./test/vitest.setup.ts'], }, plugins: [ tsconfigPaths({