fix: tests

This commit is contained in:
alina 🌸 2024-02-03 11:53:24 +03:00
parent 4e78b643df
commit 6768b15514
Signed by: teidesu
SSH key fingerprint: SHA256:uNeCpw6aTSU4aIObXLvHfLkDa82HWH9EiOj9AXOIRpI
44 changed files with 146 additions and 127 deletions

View file

@ -8,7 +8,7 @@
"main": "src/index.ts", "main": "src/index.ts",
"type": "module", "type": "module",
"scripts": { "scripts": {
"build": "pnpm run -w build-package mtcute", "build": "pnpm run -w build-package core",
"gen-client": "node ./scripts/generate-client.cjs", "gen-client": "node ./scripts/generate-client.cjs",
"gen-updates": "node ./scripts/generate-updates.cjs" "gen-updates": "node ./scripts/generate-updates.cjs"
}, },

View file

@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/require-await */
import { tl } from '@mtcute/tl' import { tl } from '@mtcute/tl'
import { MtClient, MtClientOptions } from '../network/client.js' import { MtClient, MtClientOptions } from '../network/client.js'
@ -5,7 +6,14 @@ import { ConnectionKind, RpcCallOptions } from '../network/network-manager.js'
import { StorageManagerExtraOptions } from '../storage/storage.js' import { StorageManagerExtraOptions } from '../storage/storage.js'
import { MtArgumentError } from '../types/errors.js' import { MtArgumentError } from '../types/errors.js'
import { MustEqual } from '../types/utils.js' import { MustEqual } from '../types/utils.js'
import { asyncResettable, computeNewPasswordHash, computeSrpParams, readStringSession, StringSessionData, writeStringSession } from '../utils/index.js' import {
asyncResettable,
computeNewPasswordHash,
computeSrpParams,
readStringSession,
StringSessionData,
writeStringSession,
} from '../utils/index.js'
import { LogManager } from '../utils/logger.js' import { LogManager } from '../utils/logger.js'
import { ITelegramClient } from './client.types.js' import { ITelegramClient } from './client.types.js'
import { ITelegramStorageProvider } from './storage/provider.js' import { ITelegramStorageProvider } from './storage/provider.js'
@ -29,7 +37,7 @@ export class BaseTelegramClient implements ITelegramClient {
this._serverUpdatesHandler = this.updates.handleUpdate.bind(this.updates) this._serverUpdatesHandler = this.updates.handleUpdate.bind(this.updates)
} }
this.mt.on('update', (update) => { this.mt.on('update', (update: tl.TypeUpdates) => {
this._serverUpdatesHandler(update) this._serverUpdatesHandler(update)
}) })
} }
@ -272,16 +280,10 @@ export class BaseTelegramClient implements ITelegramClient {
return this.mt.network.getPrimaryDcId() return this.mt.network.getPrimaryDcId()
} }
computeSrpParams( computeSrpParams(request: tl.account.RawPassword, password: string): Promise<tl.RawInputCheckPasswordSRP> {
request: tl.account.RawPassword,
password: string,
): Promise<tl.RawInputCheckPasswordSRP> {
return computeSrpParams(this.crypto, request, password) return computeSrpParams(this.crypto, request, password)
} }
computeNewPasswordHash( computeNewPasswordHash(algo: tl.TypePasswordKdfAlgo, password: string): Promise<Uint8Array> {
algo: tl.TypePasswordKdfAlgo,
password: string,
): Promise<Uint8Array> {
return computeNewPasswordHash(this.crypto, algo, password) return computeNewPasswordHash(this.crypto, algo, password)
} }
} }

View file

@ -4917,7 +4917,7 @@ export interface TelegramClient extends ITelegramClient {
* **Available**: both users and bots * **Available**: both users and bots
* *
*/ */
getMyUsername(): string | null getMyUsername(): Promise<string | null>
/** /**
* Get a single profile picture of a user by its ID * Get a single profile picture of a user by its ID
* *

View file

@ -103,7 +103,7 @@ describe('sendText', () => {
it('should correctly handle updateShortSentMessage with cached peer', async () => { it('should correctly handle updateShortSentMessage with cached peer', async () => {
const client = new StubTelegramClient() const client = new StubTelegramClient()
client.storage.self.store({ await client.storage.self.store({
userId: stubUser.id, userId: stubUser.id,
isBot: false, isBot: false,
isPremium: false, isPremium: false,
@ -132,7 +132,7 @@ describe('sendText', () => {
it('should correctly handle updateShortSentMessage without cached peer', async () => { it('should correctly handle updateShortSentMessage without cached peer', async () => {
const client = new StubTelegramClient() const client = new StubTelegramClient()
client.storage.self.store({ await client.storage.self.store({
userId: stubUser.id, userId: stubUser.id,
isBot: false, isBot: false,
isPremium: false, isPremium: false,

View file

@ -6,7 +6,6 @@ import { ITelegramClient } from '../../client.types.js'
* This method uses locally available information and * This method uses locally available information and
* does not call any API methods. * does not call any API methods.
*/ */
export function getMyUsername(client: ITelegramClient): string | null { export async function getMyUsername(client: ITelegramClient): Promise<string | null> {
throw new Error('Not implemented') return client.storage.self.fetch().then((self) => self?.usernames[0] ?? null)
// return getAuthState(client).selfUsername
} }

View file

@ -17,7 +17,7 @@ export async function setMyUsername(client: ITelegramClient, username: string |
username, username,
}) })
client.storage.self.update({ username }) await client.storage.self.update({ username })
return new User(res) return new User(res)
} }

View file

@ -63,7 +63,7 @@ function parse(data: Uint8Array): CurrentUserInfo | null {
if (flags & 2) { if (flags & 2) {
const len = reader.int() const len = reader.int()
usernames = new Array(len) usernames = new Array<string>(len)
for (let i = 0; i < len; i++) { for (let i = 0; i < len; i++) {
usernames[i] = reader.string() usernames[i] = reader.string()
@ -143,11 +143,7 @@ export class CurrentUserService extends BaseService {
return this._cached return this._cached
} }
async update(params: { async update(params: { username?: string; usernames?: string[]; isPremium?: boolean }): Promise<void> {
username?: string
usernames?: string[]
isPremium?: boolean
}): Promise<void> {
const info = await this.fetch() const info = await this.fetch()
if (!info) return if (!info) return

View file

@ -94,7 +94,7 @@ export function deserializeError(error: SerializedError): Error {
for (const key in custom) { for (const key in custom) {
if (key === 'code' || key === 'text') continue if (key === 'code' || key === 'text') continue
// @ts-expect-error lol // @ts-expect-error lol
err2[key] = custom[key] err2[key] = custom[key] // eslint-disable-line
} }
break break
} }

View file

@ -8,14 +8,9 @@ export class WorkerInvoker {
constructor(private send: SendFn) {} constructor(private send: SendFn) {}
private _nextId = 0 private _nextId = 0
private _pending = new Map<number, ControllablePromise<unknown>>() private _pending = new Map<number, ControllablePromise>()
private _invoke( private _invoke(target: InvokeTarget, method: string, args: unknown[], isVoid: boolean) {
target: InvokeTarget,
method: string,
args: unknown[],
isVoid: boolean,
) {
const id = this._nextId++ const id = this._nextId++
this.send({ this.send({
@ -36,15 +31,12 @@ export class WorkerInvoker {
} }
} }
invoke( invoke(target: InvokeTarget, method: string, args: unknown[]): Promise<unknown> {
target: InvokeTarget,
method: string,
args: unknown[],
): Promise<unknown> {
return this._invoke(target, method, args, false) as Promise<unknown> return this._invoke(target, method, args, false) as Promise<unknown>
} }
invokeVoid(target: InvokeTarget, method: string, args: unknown[]): void { invokeVoid(target: InvokeTarget, method: string, args: unknown[]): void {
// eslint-disable-next-line @typescript-eslint/no-floating-promises
this._invoke(target, method, args, true) this._invoke(target, method, args, true)
} }

View file

@ -6,6 +6,7 @@ export function connectToWorker(worker: SomeWorker, handler: ClientMessageHandle
const send: SendFn = worker.postMessage.bind(worker) const send: SendFn = worker.postMessage.bind(worker)
const messageHandler = (ev: MessageEvent) => { const messageHandler = (ev: MessageEvent) => {
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
handler(ev.data) handler(ev.data)
} }
@ -37,6 +38,7 @@ export function connectToWorker(worker: SomeWorker, handler: ClientMessageHandle
return return
} }
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
handler(ev.data) handler(ev.data)
} }

View file

@ -16,6 +16,7 @@ export function registerWorker(handler: WorkerMessageHandler): RespondFn {
const respond: RespondFn = port.postMessage.bind(port) const respond: RespondFn = port.postMessage.bind(port)
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
parentPort.on('message', (message) => handler(message, respond)) parentPort.on('message', (message) => handler(message, respond))
return respond return respond

View file

@ -10,6 +10,7 @@ export function registerWorker(handler: WorkerMessageHandler): RespondFn {
if (typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope) { if (typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope) {
const respond: RespondFn = self.postMessage.bind(self) const respond: RespondFn = self.postMessage.bind(self)
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
self.addEventListener('message', (message) => handler(message.data, respond)) self.addEventListener('message', (message) => handler(message.data, respond))
return respond return respond
@ -53,7 +54,7 @@ export function registerWorker(handler: WorkerMessageHandler): RespondFn {
// so even if the browser has suspended the timers, we should still get a ping within a minute // so even if the browser has suspended the timers, we should still get a ping within a minute
let timeout = setTimeout(onTimeout, 60000) let timeout = setTimeout(onTimeout, 60000)
port.addEventListener('message', async (message) => { port.addEventListener('message', (message) => {
if (message.data.__type__ === 'close') { if (message.data.__type__ === 'close') {
onClose() onClose()
@ -67,6 +68,7 @@ export function registerWorker(handler: WorkerMessageHandler): RespondFn {
return return
} }
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
handler(message.data, respond) handler(message.data, respond)
}) })
} }

View file

@ -72,14 +72,11 @@ export class TelegramWorkerPort<Custom extends WorkerCustomMethods> implements I
this._destroyed = true this._destroyed = true
if (terminate && 'terminate' in this.options.worker) { if (terminate && 'terminate' in this.options.worker) {
this.options.worker.terminate() Promise.resolve(this.options.worker.terminate()).catch(() => {})
} }
} }
invokeCustom<T extends keyof Custom>( invokeCustom<T extends keyof Custom>(method: T, ...args: Parameters<Custom[T]>): Promise<ReturnType<Custom[T]>> {
method: T,
...args: Parameters<Custom[T]>
): Promise<ReturnType<Custom[T]>> {
return this._invoker.invoke('custom', method as string, args) as Promise<ReturnType<Custom[T]>> return this._invoker.invoke('custom', method as string, args) as Promise<ReturnType<Custom[T]>>
} }

View file

@ -45,6 +45,7 @@ export function makeTelegramWorker<T extends WorkerCustomMethods>(params: Telegr
} }
} }
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const method = target[msg.method] const method = target[msg.method]
if (!method) { if (!method) {
@ -57,6 +58,7 @@ export function makeTelegramWorker<T extends WorkerCustomMethods>(params: Telegr
return return
} }
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
Promise.resolve(method.apply(target, msg.args)) Promise.resolve(method.apply(target, msg.args))
.then((res) => { .then((res) => {
if (msg.void) return if (msg.void) return

View file

@ -1,9 +1,12 @@
import { afterAll, beforeAll, describe } from 'vitest' import { afterAll, beforeAll, describe } from 'vitest'
import { testPeersRepository } from '../../../highlevel/storage/repository/peers.test-utils.js' import {
import { testRefMessagesRepository } from '../../../highlevel/storage/repository/ref-messages.test-utils.js' testAuthKeysRepository,
import { testAuthKeysRepository } from '../../repository/auth-keys.test-utils.js' testKeyValueRepository,
import { testKeyValueRepository } from '../../repository/key-value.test-utils.js' testPeersRepository,
testRefMessagesRepository,
} from '@mtcute/test'
import { IdbStorage } from './index.js' import { IdbStorage } from './index.js'
if (import.meta.env.TEST_ENV === 'browser') { if (import.meta.env.TEST_ENV === 'browser') {
@ -20,7 +23,7 @@ if (import.meta.env.TEST_ENV === 'browser') {
testRefMessagesRepository(storage.refMessages, storage.driver) testRefMessagesRepository(storage.refMessages, storage.driver)
afterAll(async () => { afterAll(async () => {
storage.driver.destroy() await storage.driver.destroy()
const req = indexedDB.deleteDatabase(idbName) const req = indexedDB.deleteDatabase(idbName)
await new Promise<void>((resolve, reject) => { await new Promise<void>((resolve, reject) => {

View file

@ -39,7 +39,7 @@ export class IdbAuthKeysRepository implements IAuthKeysRepository {
async get(dc: number): Promise<Uint8Array | null> { async get(dc: number): Promise<Uint8Array | null> {
const os = this.os() const os = this.os()
const it = await reqToPromise<AuthKeyDto>(os.get(dc)) const it = await reqToPromise<AuthKeyDto>(os.get(dc) as IDBRequest<AuthKeyDto>)
if (it === undefined) return null if (it === undefined) return null
return it.key return it.key
@ -61,7 +61,7 @@ export class IdbAuthKeysRepository implements IAuthKeysRepository {
async getTemp(dc: number, idx: number, now: number): Promise<Uint8Array | null> { async getTemp(dc: number, idx: number, now: number): Promise<Uint8Array | null> {
const os = this.osTemp() const os = this.osTemp()
const row = await reqToPromise<TempAuthKeyDto>(os.get([dc, idx])) const row = await reqToPromise<TempAuthKeyDto>(os.get([dc, idx]) as IDBRequest<TempAuthKeyDto>)
if (row === undefined || row.expiresAt! < now) return null if (row === undefined || row.expiresAt! < now) return null

View file

@ -25,7 +25,7 @@ export class IdbKvRepository implements IKeyValueRepository {
async get(key: string): Promise<Uint8Array | null> { async get(key: string): Promise<Uint8Array | null> {
const os = this.os() const os = this.os()
const res = await reqToPromise<KeyValueDto>(os.get(key)) const res = await reqToPromise<KeyValueDto>(os.get(key) as IDBRequest<KeyValueDto>)
if (res === undefined) return null if (res === undefined) return null
return res.value return res.value

View file

@ -22,19 +22,21 @@ export class IdbPeersRepository implements IPeersRepository {
} }
async getById(id: number): Promise<IPeersRepository.PeerInfo | null> { async getById(id: number): Promise<IPeersRepository.PeerInfo | null> {
const it = await reqToPromise(this.os().get(id)) const it = await reqToPromise(this.os().get(id) as IDBRequest<IPeersRepository.PeerInfo>)
return it ?? null return it ?? null
} }
async getByUsername(username: string): Promise<IPeersRepository.PeerInfo | null> { async getByUsername(username: string): Promise<IPeersRepository.PeerInfo | null> {
const it = await reqToPromise(this.os().index('by_username').get(username)) const it = await reqToPromise(
this.os().index('by_username').get(username) as IDBRequest<IPeersRepository.PeerInfo>,
)
return it ?? null return it ?? null
} }
async getByPhone(phone: string): Promise<IPeersRepository.PeerInfo | null> { async getByPhone(phone: string): Promise<IPeersRepository.PeerInfo | null> {
const it = await reqToPromise(this.os().index('by_phone').get(phone)) const it = await reqToPromise(this.os().index('by_phone').get(phone) as IDBRequest<IPeersRepository.PeerInfo>)
return it ?? null return it ?? null
} }

View file

@ -33,7 +33,7 @@ export class IdbRefMsgRepository implements IReferenceMessagesRepository {
const os = this.os() const os = this.os()
const index = os.index('by_peer') const index = os.index('by_peer')
const it = await reqToPromise<MessageRefDto>(index.get(peerId)) const it = await reqToPromise<MessageRefDto>(index.get(peerId) as IDBRequest<MessageRefDto>)
if (!it) return null if (!it) return null
return [it.chatId, it.msgId] return [it.chatId, it.msgId]

View file

@ -1,9 +1,12 @@
import { describe } from 'vitest' import { describe } from 'vitest'
import { testPeersRepository } from '../../../highlevel/storage/repository/peers.test-utils.js' import {
import { testRefMessagesRepository } from '../../../highlevel/storage/repository/ref-messages.test-utils.js' testAuthKeysRepository,
import { testAuthKeysRepository } from '../../repository/auth-keys.test-utils.js' testKeyValueRepository,
import { testKeyValueRepository } from '../../repository/key-value.test-utils.js' testPeersRepository,
testRefMessagesRepository,
} from '@mtcute/test'
import { MemoryStorage } from './index.js' import { MemoryStorage } from './index.js'
describe('memory storage', () => { describe('memory storage', () => {

View file

@ -1,4 +1,2 @@
export * from '../../highlevel/storage/repository/peers.js'
export * from '../../highlevel/storage/repository/ref-messages.js'
export * from './auth-keys.js' export * from './auth-keys.js'
export * from './key-value.js' export * from './key-value.js'

View file

@ -1,7 +1,7 @@
import { describe, expect, it, vi } from 'vitest' import { describe, expect, it, vi } from 'vitest'
import { fakeAuthKeysRepository } from '../repository/auth-keys.test-utils.js' import { fakeAuthKeysRepository, fakeKeyValueRepository } from '@mtcute/test'
import { fakeKeyValueRepository } from '../repository/key-value.test-utils.js'
import { AuthKeysService } from './auth-keys.js' import { AuthKeysService } from './auth-keys.js'
import { FutureSaltsService } from './future-salts.js' import { FutureSaltsService } from './future-salts.js'
import { testServiceOptions } from './utils.test-utils.js' import { testServiceOptions } from './utils.test-utils.js'

View file

@ -1,6 +1,7 @@
import { describe, expect, it, vi } from 'vitest' import { describe, expect, it, vi } from 'vitest'
import { fakeKeyValueRepository } from '../repository/key-value.test-utils.js' import { fakeKeyValueRepository } from '@mtcute/test'
import { UpdatesStateService } from '../../highlevel/storage/service/updates.js' import { UpdatesStateService } from '../../highlevel/storage/service/updates.js'
import { testServiceOptions } from './utils.test-utils.js' import { testServiceOptions } from './utils.test-utils.js'
@ -73,10 +74,7 @@ describe('updates state service', () => {
it('should write to updates_channel:xxx key', async () => { it('should write to updates_channel:xxx key', async () => {
await service.setChannelPts(123, 0x04030201) await service.setChannelPts(123, 0x04030201)
expect(kv.set).toHaveBeenCalledWith( expect(kv.set).toHaveBeenCalledWith('updates_channel:123', new Uint8Array([1, 2, 3, 4]))
'updates_channel:123',
new Uint8Array([1, 2, 3, 4]),
)
}) })
}) })
}) })

View file

@ -62,7 +62,9 @@ export class StorageManager {
this.driver.setup?.(this.log) this.driver.setup?.(this.log)
if (this.options.cleanup ?? true) { if (this.options.cleanup ?? true) {
this._cleanupRestore = beforeExit(() => this._destroy().catch((err) => this.log.error(err))) this._cleanupRestore = beforeExit(() => {
this._destroy().catch((err) => this.log.error('cleanup error: %s', err))
})
} }
await this.driver.load?.() await this.driver.load?.()

View file

@ -51,8 +51,9 @@ export function asyncResettable<T extends(...args: any[]) => Promise<any>>(func:
return runningPromise return runningPromise
} }
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
runningPromise = func(...args) runningPromise = func(...args)
runningPromise.then(() => { void runningPromise.then(() => {
runningPromise = null runningPromise = null
finished = true finished = true
}) })

View file

@ -125,7 +125,12 @@ describe('readStringSession', () => {
testMode: false, testMode: false,
primaryDcs: stubDcs, primaryDcs: stubDcs,
authKey: stubAuthKey, authKey: stubAuthKey,
self: { userId: 12345, isBot: false }, self: {
userId: 12345,
isBot: false,
isPremium: false,
usernames: [],
},
}) })
}) })
@ -140,7 +145,12 @@ describe('readStringSession', () => {
testMode: true, testMode: true,
primaryDcs: stubDcs, primaryDcs: stubDcs,
authKey: stubAuthKey, authKey: stubAuthKey,
self: { userId: 12345, isBot: false }, self: {
userId: 12345,
isBot: false,
isPremium: false,
usernames: [],
},
}) })
}) })
}) })
@ -158,7 +168,12 @@ describe('readStringSession', () => {
// v1 didn't have separate media dc // v1 didn't have separate media dc
primaryDcs: stubDcsSameMedia, primaryDcs: stubDcsSameMedia,
authKey: stubAuthKey, authKey: stubAuthKey,
self: { userId: 12345, isBot: false }, self: {
userId: 12345,
isBot: false,
isPremium: false,
usernames: [],
},
}) })
}) })
}) })

View file

@ -1,7 +1,7 @@
import { describe, expect, it } from 'vitest' import { describe, expect, it } from 'vitest'
import { CallbackQuery, MtArgumentError, PeersIndex } from '@mtcute/client' import { CallbackQuery, MtArgumentError, PeersIndex } from '@mtcute/core'
import { utf8EncodeToBuffer } from '@mtcute/client/utils.js' import { utf8EncodeToBuffer } from '@mtcute/core/utils.js'
import { createStub } from '@mtcute/test' import { createStub } from '@mtcute/test'
import { CallbackDataBuilder } from './callback-data-builder.js' import { CallbackDataBuilder } from './callback-data-builder.js'

View file

@ -20,12 +20,12 @@ describe('filters.command', () => {
const ctx = createMessageContext({ const ctx = createMessageContext({
message: text, message: text,
}) })
// todo void ctx.client.storage.self.store({
// ctx.client.getAuthState = () => ({ isBot: true,
// isBot: true, isPremium: false,
// userId: 0, userId: 0,
// selfUsername: 'testbot', usernames: ['testbot'],
// }) })
// eslint-disable-next-line // eslint-disable-next-line
if (command(...params)(ctx)) return (ctx as any).command if (command(...params)(ctx)) return (ctx as any).command
@ -39,11 +39,10 @@ describe('filters.command', () => {
expect(getParsedCommand('/start', ['start', 'stop'])).toEqual(['start']) expect(getParsedCommand('/start', ['start', 'stop'])).toEqual(['start'])
}) })
// todo it('should only parse commands to the current bot', () => {
// it('should only parse commands to the current bot', () => { expect(getParsedCommand('/start@testbot', 'start')).toEqual(['start'])
// expect(getParsedCommand('/start@testbot', 'start')).toEqual(['start']) expect(getParsedCommand('/start@otherbot', 'start')).toEqual(null)
// expect(getParsedCommand('/start@otherbot', 'start')).toEqual(null) })
// })
it('should parse command arguments', () => { it('should parse command arguments', () => {
expect(getParsedCommand('/start foo bar baz', 'start')).toEqual(['start', 'foo', 'bar', 'baz']) expect(getParsedCommand('/start foo bar baz', 'start')).toEqual(['start', 'foo', 'bar', 'baz'])

View file

@ -18,15 +18,14 @@ export class StateService {
async load() { async load() {
await this._load.run() await this._load.run()
this._vacuumTimer = setInterval(() => { this._vacuumTimer = setInterval(() => {
Promise.resolve(this.provider.state.vacuum(Date.now())) Promise.resolve(this.provider.state.vacuum(Date.now())).catch(() => {})
.catch(() => {})
}, 300_000) }, 300_000)
} }
async destroy() { async destroy() {
await this.provider.driver.save?.() await this.provider.driver.save?.()
await this.provider.driver.destroy?.() await this.provider.driver.destroy?.()
clearInterval(this._vacuumTimer!) clearInterval(this._vacuumTimer)
this._loaded = false this._loaded = false
} }

View file

@ -1,6 +1,6 @@
import { describe, expect, it } from 'vitest' import { describe, expect, it } from 'vitest'
import { PeersIndex, TelegramClient } from '@mtcute/client' import { PeersIndex, TelegramClient } from '@mtcute/core'
import { Dispatcher, PropagationAction } from '../src/index.js' import { Dispatcher, PropagationAction } from '../src/index.js'

View file

@ -1,7 +1,7 @@
import Long from 'long' import Long from 'long'
import { describe, expect, it } from 'vitest' import { describe, expect, it } from 'vitest'
import { MessageEntity, TextWithEntities, tl } from '@mtcute/client' import { MessageEntity, TextWithEntities, tl } from '@mtcute/core'
// prettier has "html" special-cased which breaks the formatting // prettier has "html" special-cased which breaks the formatting
// this is not an issue when using normally, since we properly handle newlines/spaces, // this is not an issue when using normally, since we properly handle newlines/spaces,

View file

@ -1,6 +1,6 @@
import { describe, expect, it } from 'vitest' import { describe, expect, it } from 'vitest'
import { Message, PeersIndex } from '@mtcute/client' import { Message, PeersIndex } from '@mtcute/core'
import { MessageContext } from '@mtcute/dispatcher' import { MessageContext } from '@mtcute/dispatcher'
import { createMtcuteI18n, OtherLanguageWrap } from '../src/index.js' import { createMtcuteI18n, OtherLanguageWrap } from '../src/index.js'

View file

@ -1,7 +1,7 @@
import Long from 'long' import Long from 'long'
import { describe, expect, it } from 'vitest' import { describe, expect, it } from 'vitest'
import { MessageEntity, TextWithEntities, tl } from '@mtcute/client' import { MessageEntity, TextWithEntities, tl } from '@mtcute/core'
// md is special cased in prettier, we don't want that here // md is special cased in prettier, we don't want that here
import { md as md_ } from './index.js' import { md as md_ } from './index.js'

View file

@ -18,7 +18,7 @@ function mapPeerDto(dto: PeerDto): IPeersRepository.PeerInfo {
return { return {
id: dto.id, id: dto.id,
accessHash: dto.hash, accessHash: dto.hash,
usernames: JSON.parse(dto.usernames), usernames: JSON.parse(dto.usernames) as string[],
updated: dto.updated, updated: dto.updated,
phone: dto.phone || undefined, phone: dto.phone || undefined,
complete: dto.complete, complete: dto.complete,
@ -47,7 +47,9 @@ export class SqlitePeersRepository implements IPeersRepository {
) )
this._getById = db.prepare('select * from peers where id = ?') this._getById = db.prepare('select * from peers where id = ?')
this._getByUsername = db.prepare('select * from peers where exists (select 1 from json_each(usernames) where value = ?)') this._getByUsername = db.prepare(
'select * from peers where exists (select 1 from json_each(usernames) where value = ?)',
)
this._getByPhone = db.prepare('select * from peers where phone = ?') this._getByPhone = db.prepare('select * from peers where phone = ?')
this._delAll = db.prepare('delete from peers') this._delAll = db.prepare('delete from peers')

View file

@ -1,10 +1,12 @@
import { afterAll, beforeAll, describe } from 'vitest' import { afterAll, beforeAll, describe } from 'vitest'
import { testAuthKeysRepository } from '@mtcute/core/src/storage/repository/auth-keys.test-utils.js'
import { testKeyValueRepository } from '@mtcute/core/src/storage/repository/key-value.test-utils.js'
import { testPeersRepository } from '@mtcute/core/src/storage/repository/peers.test-utils.js'
import { testRefMessagesRepository } from '@mtcute/core/src/storage/repository/ref-messages.test-utils.js'
import { LogManager } from '@mtcute/core/utils.js' import { LogManager } from '@mtcute/core/utils.js'
import {
testAuthKeysRepository,
testKeyValueRepository,
testPeersRepository,
testRefMessagesRepository,
} from '@mtcute/test'
import { SqliteStorage } from '../src/index.js' import { SqliteStorage } from '../src/index.js'
@ -12,9 +14,9 @@ if (import.meta.env.TEST_ENV === 'node') {
describe('SqliteStorage', () => { describe('SqliteStorage', () => {
const storage = new SqliteStorage(':memory:') const storage = new SqliteStorage(':memory:')
beforeAll(() => { beforeAll(async () => {
storage.driver.setup(new LogManager()) storage.driver.setup(new LogManager())
storage.driver.load() await storage.driver.load()
}) })
testAuthKeysRepository(storage.authKeys) testAuthKeysRepository(storage.authKeys)

View file

@ -24,6 +24,7 @@ export class StubTelegramClient extends BaseTelegramClient {
apiHash: '', apiHash: '',
logLevel: 0, logLevel: 0,
storage, storage,
disableUpdates: true,
transport: () => { transport: () => {
const transport = new StubTelegramTransport({ const transport = new StubTelegramTransport({
onMessage: (data) => { onMessage: (data) => {
@ -279,15 +280,8 @@ export class StubTelegramClient extends BaseTelegramClient {
// helpers // // helpers //
async connectAndWait() {
await this.connect()
await new Promise((resolve): void => {
this.mt.once('usable', resolve)
})
}
async with(fn: () => MaybeAsync<void>): Promise<void> { async with(fn: () => MaybeAsync<void>): Promise<void> {
await this.connectAndWait() await this.connect()
let error: unknown let error: unknown

View file

@ -1,7 +1,7 @@
export * from './client.js' export * from './client.js'
export * from './crypto.js' export * from './crypto.js'
export * from './storage.js' export * from './storage.js'
// export * from './storage-test.js' // todo export * from './storage/index.js'
export * from './stub.js' export * from './stub.js'
export * from './transport.js' export * from './transport.js'
export * from './types.js' export * from './types.js'

View file

@ -1,6 +1,6 @@
import { afterEach, describe, expect, it, vi } from 'vitest' import { afterEach, describe, expect, it, vi } from 'vitest'
import { IAuthKeysRepository } from './auth-keys.js' import { IAuthKeysRepository } from '@mtcute/core'
export function fakeAuthKeysRepository(): IAuthKeysRepository { export function fakeAuthKeysRepository(): IAuthKeysRepository {
return { return {

View file

@ -0,0 +1,4 @@
export * from './auth-keys.js'
export * from './key-value.js'
export * from './peers.js'
export * from './ref-messages.js'

View file

@ -1,7 +1,6 @@
import { afterEach, describe, expect, it, vi } from 'vitest' import { afterEach, describe, expect, it, vi } from 'vitest'
import { IStorageDriver } from '../driver.js' import { IKeyValueRepository, IStorageDriver } from '@mtcute/core'
import { IKeyValueRepository } from './key-value.js'
export function fakeKeyValueRepository(): IKeyValueRepository { export function fakeKeyValueRepository(): IKeyValueRepository {
return { return {

View file

@ -1,11 +1,10 @@
import { describe, expect, it, vi } from 'vitest' import { describe, expect, it, vi } from 'vitest'
import { createStub } from '@mtcute/test' import { IPeersRepository, IStorageDriver } from '@mtcute/core'
import { TlBinaryWriter } from '@mtcute/core/utils.js'
import { __tlWriterMap } from '@mtcute/tl/binary/writer.js' import { __tlWriterMap } from '@mtcute/tl/binary/writer.js'
import { TlBinaryWriter } from '@mtcute/tl-runtime'
import { IStorageDriver } from '../../../storage/driver.js' import { createStub } from '../stub.js'
import { IPeersRepository } from './peers.js'
export function fakePeersRepository(): IPeersRepository { export function fakePeersRepository(): IPeersRepository {
return { return {
@ -56,8 +55,8 @@ export function testPeersRepository(repo: IPeersRepository, driver: IStorageDriv
}) })
it('should store and retrieve peers', async () => { it('should store and retrieve peers', async () => {
repo.store(stubPeerUser) await repo.store(stubPeerUser)
repo.store(stubPeerChannel) await repo.store(stubPeerChannel)
await driver.save?.() await driver.save?.()
expect(fixPeerInfo(await repo.getById(123123))).toEqual(stubPeerUser) expect(fixPeerInfo(await repo.getById(123123))).toEqual(stubPeerUser)
@ -69,11 +68,11 @@ export function testPeersRepository(repo: IPeersRepository, driver: IStorageDriv
}) })
it('should update peers usernames', async () => { it('should update peers usernames', async () => {
repo.store(stubPeerUser) await repo.store(stubPeerUser)
await driver.save?.() await driver.save?.()
const modUser = { ...stubPeerUser, usernames: ['some_user2'] } const modUser = { ...stubPeerUser, usernames: ['some_user2'] }
repo.store(modUser) await repo.store(modUser)
await driver.save?.() await driver.save?.()
expect(fixPeerInfo(await repo.getById(123123))).toEqual(modUser) expect(fixPeerInfo(await repo.getById(123123))).toEqual(modUser)

View file

@ -1,7 +1,6 @@
import { afterEach, describe, expect, it, vi } from 'vitest' import { afterEach, describe, expect, it, vi } from 'vitest'
import { IStorageDriver } from '../../../storage/driver.js' import { IReferenceMessagesRepository, IStorageDriver } from '@mtcute/core'
import { IReferenceMessagesRepository } from './ref-messages.js'
export function fakeRefMessagesRepository(): IReferenceMessagesRepository { export function fakeRefMessagesRepository(): IReferenceMessagesRepository {
return { return {
@ -27,7 +26,10 @@ export function testRefMessagesRepository(repo: IReferenceMessagesRepository, dr
await repo.store(2, 6, 7) await repo.store(2, 6, 7)
await driver.save?.() await driver.save?.()
expect(await repo.getByPeer(1)).deep.oneOf([[2, 3], [4, 5]]) expect(await repo.getByPeer(1)).deep.oneOf([
[2, 3],
[4, 5],
])
expect(await repo.getByPeer(2)).toEqual([6, 7]) expect(await repo.getByPeer(2)).toEqual([6, 7])
expect(await repo.getByPeer(3)).toEqual(null) expect(await repo.getByPeer(3)).toEqual(null)
expect(await repo.getByPeer(4)).toEqual(null) expect(await repo.getByPeer(4)).toEqual(null)
@ -64,7 +66,11 @@ export function testRefMessagesRepository(repo: IReferenceMessagesRepository, dr
await repo.deleteByPeer(1) await repo.deleteByPeer(1)
await driver.save?.() await driver.save?.()
expect(await repo.getByPeer(1)).toEqual(null) expect(await repo.getByPeer(1)).toEqual(null)
expect(await repo.getByPeer(2)).deep.oneOf([[20, 30], [40, 50], [60, 70]]) expect(await repo.getByPeer(2)).deep.oneOf([
[20, 30],
[40, 50],
[60, 70],
])
}) })
}) })
} }

View file

@ -1,8 +1,8 @@
import EventEmitter from 'events' import EventEmitter from 'events'
import { tl } from '@mtcute/tl'
import { ITelegramTransport, TransportState } from '@mtcute/core' import { ITelegramTransport, TransportState } from '@mtcute/core'
import { ICryptoProvider, Logger } from '@mtcute/core/utils.js' import { ICryptoProvider, Logger } from '@mtcute/core/utils.js'
import { tl } from '@mtcute/tl'
export class StubTelegramTransport extends EventEmitter implements ITelegramTransport { export class StubTelegramTransport extends EventEmitter implements ITelegramTransport {
constructor( constructor(

View file

@ -9,6 +9,7 @@ import { readFile, writeFile } from 'fs/promises'
import { join } from 'path' import { join } from 'path'
import * as readline from 'readline' import * as readline from 'readline'
import { hasPresentKey, isPresent } from '@mtcute/core/utils.js'
import { import {
generateTlSchemasDifference, generateTlSchemasDifference,
mergeTlEntries, mergeTlEntries,
@ -19,7 +20,6 @@ import {
TlFullSchema, TlFullSchema,
writeTlEntryToString, writeTlEntryToString,
} from '@mtcute/tl-utils' } from '@mtcute/tl-utils'
import { hasPresentKey, isPresent } from '@mtcute/core/utils.js'
import { import {
__dirname, __dirname,