quickblox 2.23.1-beta.4 → 2.23.1-beta.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -206,57 +206,69 @@ Outbound-ветка (568-581) — симметрично (`statistic.local[media
206
206
  PR, что и guard. Если откладываем — фиксируем как follow-up внутри QC-1682, без
207
207
  нового номера.
208
208
 
209
- ## 5. Тестирование реалистичная оценка (ВАЖНО, честно)
210
-
211
- `_getStats` **приватная функция** (`function _getStats(...)` в модуле, НЕ на прототипе,
212
- НЕ экспортируется). `QB-WebRTCSpec.js` (79 строк) **integration-тест**: реальный
213
- `QB.init` + `QB.chat.connect` к серверу (креды из `spec/config`), и почти всё `pending()`
214
- под Node (`WebRTC API isn't supported outside of the browser`). getStats там НЕ покрыт.
215
-
216
- Из этого следует: **изолированный юнит-тест на `_getStats` без вмешательства в файл
217
- или новой dev-зависимости невозможен**, а integration-путь требует браузера + живого
218
- `RTCPeerConnection` и не воспроизводит `mediaType=undefined` детерминированно. Варианты,
219
- что реально доступно:
220
-
221
- - **Вариант T1 (минимум, рекомендую для этого точечного guard):** без нового авто-теста.
222
- Обоснование: правка чистый guard + warn, не меняет поведение для валидных `mediaType`
223
- (`item` существует идентичный путь); меняет только путь `mediaType ∉ {audio,video}`
224
- (раньше краш → теперь skip + traceWarning). Проверка — `lint` + существующие
225
- `test:pr` (регрессия, что ничего не сломали) + ручная сверка `git diff`.
226
- - **Вариант T1.5 (рассмотреть, если когда-то понадобится покрытие `_getStats`):** юнит-тест
227
- через `rewire` / `proxyquire` эти библиотеки умеют доставать приватные функции из
228
- модуля через `__get__` API, **не меняя production-код**. Файл `qbRTCPeerConnection.js`
229
- не модифицируется, тест получает реальный `_getStats` и проверяет его на fake-peer'е
230
- с `getStats: () => Promise.resolve([{ type: 'inbound-rtp', bytesReceived: 100,
231
- mediaType: undefined }])`. Покрытие 100% настоящего кода без рефактора. **Цена:**
232
- `rewire` новая dev-зависимость, требует отдельного approval (CLAUDE.md DO NOT
233
- запрещает `npm install` без подтверждения). **Не для этого PR**: если ставим rewire —
234
- это отдельный шаг «инфраструктура тестов», не часть guard-фикса.
235
- - **Вариант T2 (если нужен авто-тест без новых dev-зависимостей):** вынести «нормализатор
236
- одного stats-report» в чистую экспортируемую утилиту (напр.
237
- `applyStatReport(statistic, result, lastResults)`), написать на неё jasmine-тест в Node
238
- (без браузера) с кейсами `mediaType: 'video' | 'audio' | undefined | 'application'`.
239
- Это уже **рефактор-фикс**, шире guard'а — отдельное решение пользователя (риск задеть
240
- рабочий код ради тестируемости).
241
-
242
- **Рекомендация:** **T1** для самого фикса. T1.5 — кандидат на будущий PR (`mediaType ||
243
- kind` fallback из §4), там покрытие важнее и rewire оправдан. T2 — только если команда
244
- SDK хочет покрытие, но без новых dev-зависимостей.
245
-
246
- ### Сравнительная таблица
247
-
248
- | Вариант | Меняет prod-код | Новые deps | Покрытие настоящего `_getStats` | Риск регрессии |
249
- |---|---|---|---|---|
250
- | T1 (рекомендую) | Нет | Нет | 0% (только lint + regression) | Минимальный |
251
- | T1.5 (rewire) | Нет | +rewire (требует approval) | 100% | Минимальный |
252
- | T2 (рефактор) | Да | Нет | 100% | Средний (риск задеть смежное) |
209
+ ## 5. Тестирование (РЕШЕНО: авто-тест на `_applyStatReport`)
210
+
211
+ **СОСТОЯНИЕ на 2026-05-31 (сверено):** инфраструктура теста уже готова другим агентом —
212
+ тестировать решено через выделенную функцию `_applyStatReport`, БЕЗ новых dev-зависимостей
213
+ (rewire не нужен):
214
+ - `qbRTCPeerConnection._applyStatReport = _applyStatReport;` (строка **832**) функция
215
+ экспонирована как статик-свойство модуля. Чистая, синхронная, без сети/браузера.
216
+ - Создан спек `spec/QB-WebRTCStatsSpec.js` (113 строк) `require` модуля напрямую под
217
+ Node, `apply = RTCPeerConnection._applyStatReport`, `freshStatistic()` хелпер.
218
+ - Спек **зарегистрирован во всех 3 jasmine-конфигах** (`jasmine.json`, `jasmine.pr.json`,
219
+ `jasmine.full.json`) подхватывается `npm test` и `npm run test:pr`.
220
+
221
+ **Уже покрыто (6 кейсов, guard-часть):** inbound video, inbound audio, `mediaType=undefined`
222
+ (не бросает, remote не мутируется), `mediaType='application'` (skip), outbound video
223
+ (симметрия), `remote-candidate` (рефактор не сломал candidate-ветку).
224
+
225
+ ### ОСТАЛОСЬ ДОБАВИТЬ кейсы на `kind`-fallback (сердцевина варианта 1)
226
+
227
+ Текущий тест НЕ проверяет fallback (его в коде ещё нет). После добавления fallback (§4)
228
+ дописать в `QB-WebRTCStatsSpec.js`:
229
+
230
+ 1. **Safari inbound video `kind` без `mediaType`:**
231
+ ```js
232
+ it('fills statistic.remote.video when only kind is present (Safari)', function() {
233
+ var statistic = freshStatistic();
234
+ apply(statistic, {
235
+ type: 'inbound-rtp', kind: 'video', mediaType: undefined,
236
+ bytesReceived: 1000, packetsReceived: 10, timestamp: 12345
237
+ }, null);
238
+ expect(statistic.remote.video.bytesReceived).toEqual(1000);
239
+ });
240
+ ```
241
+ 2. **Safari inbound audio — `kind` без `mediaType`** (аналогично, `kind:'audio'`,
242
+ проверить `statistic.remote.audio.bytesReceived`).
243
+ 3. **Safari outbound video `kind` без `mediaType`** (`type:'outbound-rtp'`, `kind:'video'`,
244
+ `bytesSent`, проверить `statistic.local.video.bytesSent`).
245
+ 4. **Приоритет `mediaType` над `kind`** (на случай конфликта): `mediaType:'video'`,
246
+ `kind:'audio'` пишется в `remote.video` (т.к. `mediaType || kind` → `mediaType`).
247
+ Защищает от регрессии, если кто-то поменяет порядок на `kind || mediaType`.
248
+ 5. **Ни `mediaType`, ни `kind`** skip, не бросает, remote не мутируется
249
+ (этот кейс частично есть как `mediaType=undefined`, но без `kind` — дополнить, что и
250
+ `kind` отсутствует, чтобы fallback тоже резолвился в `undefined`).
251
+ 6. **(желательно) framerate на Safari:** inbound `kind:'video'`, `framerateMean: 30`,
252
+ `lastResults` с предыдущим timestamp `statistic.remote.video.framesPerSecond`
253
+ заполнен. Это прямая проверка, что нормализация `mediaType` в переменную (см. §4)
254
+ починила и framerate-ветку, а не только индексацию.
255
+
256
+ ### Замечание по browser-ветке спека (не блокер для PR)
257
+
258
+ Строка 9 спека: `window.QB.webrtc.RTCPeerConnection` — путь для браузер-прогона. Под Node
259
+ (`isNodeEnv=true`, как в `test:pr`) не используется. Перед браузер-прогоном стоит
260
+ подтвердить, что `QB.webrtc.RTCPeerConnection` — реальный публичный путь; для PR-проверки
261
+ (Node) не критично.
253
262
 
254
263
  ## 6. Сборка / проверка (клон 05)
255
264
 
256
265
  `node_modules` на месте — `npm i` не требуется. Скрипты (из package.json):
257
- 1. `git diff` — только строки 547-564 (2 блока).
266
+ 1. `git diff` — функция `_applyStatReport` в `qbRTCPeerConnection.js` (+ статик-экспорт стр.
267
+ 832) + спек `spec/QB-WebRTCStatsSpec.js`. Финальная правка добавит лишь `kind`-fallback
268
+ к функции и fallback-кейсы в спек.
258
269
  2. `npm run lint` (jshint) — должно быть чисто.
259
- 3. `npm run test:pr` (jasmine PR-набор, включает `QB-WebRTCSpec.js`) регрессия зелёная.
270
+ 3. `npm run test:pr` (jasmine PR-набор, включает `QB-WebRTCSpec.js` + `QB-WebRTCStatsSpec.js`)
271
+ — все кейсы зелёные (6 guard + новые fallback).
260
272
  4. (опц.) `npm run test:node-regression` (`spec/phase-a-upgrade-check.js`).
261
273
  5. `npm run build` НЕ обязателен для PR кода (dist собирается отдельно), но если нужен
262
274
  собранный артефакт для проверки на проекте — `npm run build` (lint+gulp+minify).
@@ -296,12 +308,13 @@ SDK хочет покрытие, но без новых dev-зависимост
296
308
  Safari-статистику (QC-1645/QC-1475). Оба в одном `[QC-1682]`-PR. Guard уже в коде;
297
309
  остался fallback (§4).
298
310
 
299
- **ОТКРЫТО (нужно решение перед финальной правкой):**
300
- 1. **Авто-тест на `_applyStatReport`?** Функция уже выделена другим агентом, поэтому
301
- юнит-тест без новых dev-зависимостей теперь возможен (jasmine, Node): передать
302
- fake-`statistic` + fake-`result` с разными `mediaType`/`kind`, проверить заполнение и
303
- skip. Варианты: **T-да** (написать тест рекомендую, раз функция уже тестопригодна) /
304
- **T-нет** (только lint+test:pr регрессия). Цена T-да минимальна (функция чистая).
311
+ - **Авто-тест РЕШЕНО: ДА.** Через `_applyStatReport` (статик `qbRTCPeerConnection._applyStatReport`,
312
+ строка 832), спек `spec/QB-WebRTCStatsSpec.js` уже создан и зарегистрирован в jasmine-конфигах.
313
+ Guard-кейсы (6) уже написаны; остаётся дописать `kind`-fallback-кейсы (см. §5, 6 шт.).
314
+
315
+ **Открытых вопросов перед кодом не осталось.** Оставшаяся работа агента:
316
+ (1) `kind`-fallback в `_applyStatReport` (§4), (2) fallback-тест-кейсы (§5), (3) lint +
317
+ test:pr, (4) подготовить текст коммита `[QC-1682]` для пользователя.
305
318
 
306
319
  ## 9. Доставка фикса до прода — вариант A (РЕШЕНО 2026-05-30)
307
320
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "quickblox",
3
3
  "description": "QuickBlox JavaScript SDK",
4
- "version": "2.23.1-beta.4",
4
+ "version": "2.23.1-beta.5",
5
5
  "homepage": "https://quickblox.com/developers/Javascript",
6
6
  "main": "src/qbMain.js",
7
7
  "types": "quickblox.d.ts",
package/quickblox.js CHANGED
@@ -36938,34 +36938,38 @@ function _getStats(peer, lastResults, successCallback, errorCallback) {
36938
36938
 
36939
36939
  function _applyStatReport(statistic, result, lastResults) {
36940
36940
  var item;
36941
+ // mediaType is deprecated in the W3C webrtc-stats spec and replaced by kind.
36942
+ // Safari/WebKit omits mediaType on some reports and provides only kind, so we
36943
+ // normalize once and use it for both the statistic lookup and the 'video' check.
36944
+ var mediaType = result.mediaType || result.kind;
36941
36945
 
36942
36946
  if (result.bytesReceived && result.type === 'inbound-rtp') {
36943
- item = statistic.remote[result.mediaType];
36947
+ item = statistic.remote[mediaType];
36944
36948
 
36945
36949
  if (item) {
36946
36950
  item.bitrate = _getBitratePerSecond(result, lastResults, false);
36947
36951
  item.bytesReceived = result.bytesReceived;
36948
36952
  item.packetsReceived = result.packetsReceived;
36949
36953
  item.timestamp = result.timestamp;
36950
- if (result.mediaType === 'video' && result.framerateMean) {
36954
+ if (mediaType === 'video' && result.framerateMean) {
36951
36955
  item.framesPerSecond = Math.round(result.framerateMean * 10) / 10;
36952
36956
  }
36953
36957
  } else {
36954
- Helpers.traceWarning('_getStats: skipping inbound-rtp report with unknown mediaType: ' + result.mediaType);
36958
+ Helpers.traceWarning('_getStats: skipping inbound-rtp report with unknown mediaType/kind: ' + mediaType);
36955
36959
  }
36956
36960
  } else if (result.bytesSent && result.type === 'outbound-rtp') {
36957
- item = statistic.local[result.mediaType];
36961
+ item = statistic.local[mediaType];
36958
36962
 
36959
36963
  if (item) {
36960
36964
  item.bitrate = _getBitratePerSecond(result, lastResults, true);
36961
36965
  item.bytesSent = result.bytesSent;
36962
36966
  item.packetsSent = result.packetsSent;
36963
36967
  item.timestamp = result.timestamp;
36964
- if (result.mediaType === 'video' && result.framerateMean) {
36968
+ if (mediaType === 'video' && result.framerateMean) {
36965
36969
  item.framesPerSecond = Math.round(result.framerateMean * 10) / 10;
36966
36970
  }
36967
36971
  } else {
36968
- Helpers.traceWarning('_getStats: skipping outbound-rtp report with unknown mediaType: ' + result.mediaType);
36972
+ Helpers.traceWarning('_getStats: skipping outbound-rtp report with unknown mediaType/kind: ' + mediaType);
36969
36973
  }
36970
36974
  } else if (result.type === 'local-candidate') {
36971
36975
  item = statistic.local.candidate;
@@ -39719,7 +39723,7 @@ module.exports = StreamManagement;
39719
39723
  */
39720
39724
 
39721
39725
  var config = {
39722
- version: '2.23.1-beta.4',
39726
+ version: '2.23.1-beta.5',
39723
39727
  buildNumber: '1179',
39724
39728
  creds: {
39725
39729
  'appId': 0,