How to use doc2 method in wpt

Best JavaScript code snippet using wpt

presence.js

Source:presence.js Github

copy

Full Screen

1var async = require('async');2var util = require('../util');3var errorHandler = util.errorHandler;4var Backend = require('../../lib/backend');5var ShareDBError = require('../../lib/error');6var expect = require('expect.js');7var types = require('../../lib/types');8var presenceType = require('./presence-type');9types.register(presenceType.type);10types.register(presenceType.type2);11types.register(presenceType.type3);12[13 'wrapped-presence-no-compare',14 'wrapped-presence-with-compare',15 'unwrapped-presence'16].forEach(function(typeName) {17 function p(index) {18 return typeName === 'unwrapped-presence' ? index : { index: index };19 }20 describe('client presence (' + typeName + ')', function() {21 beforeEach(function() {22 this.backend = new Backend();23 this.connection = this.backend.connect();24 this.connection2 = this.backend.connect();25 this.doc = this.connection.get('dogs', 'fido');26 this.doc2 = this.connection2.get('dogs', 'fido');27 });28 afterEach(function(done) {29 this.backend.close(done);30 });31 it('sends presence immediately', function(allDone) {32 async.series([33 this.doc.create.bind(this.doc, [], typeName),34 this.doc.subscribe.bind(this.doc),35 this.doc2.subscribe.bind(this.doc2),36 function(done) {37 this.doc.requestReplyPresence = false;38 this.doc.submitPresence(p(1), errorHandler(done));39 this.doc2.once('presence', function(srcList, submitted) {40 expect(srcList).to.eql([ this.connection.id ]);41 expect(submitted).to.equal(true);42 expect(this.doc2.data).to.eql([]);43 expect(this.doc2.presence[this.connection.id]).to.eql(p(1));44 done();45 }.bind(this));46 }.bind(this)47 ], allDone);48 });49 it('sends presence after pending ops', function(allDone) {50 async.series([51 this.doc.create.bind(this.doc, [], typeName),52 this.doc.subscribe.bind(this.doc),53 this.doc2.subscribe.bind(this.doc2),54 function(done) {55 this.doc.submitOp({ index: 0, value: 'a' }, errorHandler(done));56 this.doc.submitOp({ index: 1, value: 'b' }, errorHandler(done));57 this.doc.requestReplyPresence = false;58 this.doc.submitPresence(p(1), errorHandler(done));59 this.doc2.once('presence', function(srcList, submitted) {60 expect(srcList).to.eql([ this.connection.id ]);61 expect(submitted).to.equal(true);62 expect(this.doc2.data).to.eql([ 'a', 'b' ]);63 expect(this.doc2.presence[this.connection.id]).to.eql(p(1));64 done();65 }.bind(this));66 }.bind(this)67 ], allDone);68 });69 it('waits for pending ops before processing future presence', function(allDone) {70 async.series([71 this.doc.create.bind(this.doc, [], typeName),72 this.doc.subscribe.bind(this.doc),73 this.doc2.subscribe.bind(this.doc2),74 function(done) {75 this.doc2.on('presence', function(srcList, submitted) {76 expect(srcList).to.eql([ this.connection.id ]);77 expect(submitted).to.equal(true);78 expect(this.doc2.data).to.eql([ 'a', 'b' ]);79 expect(this.doc2.presence[this.connection.id]).to.eql(p(1));80 done();81 }.bind(this));82 // A hack to send presence for a future version.83 this.doc.version += 2;84 this.doc.requestReplyPresence = false;85 this.doc.submitPresence(p(1), function(err) {86 if (err) return done(err);87 this.doc.version -= 2;88 this.doc.submitOp({ index: 0, value: 'a' }, errorHandler(done));89 this.doc.submitOp({ index: 1, value: 'b' }, errorHandler(done));90 }.bind(this));91 }.bind(this)92 ], allDone);93 });94 it('handles presence sent for earlier revisions (own ops, presence.index < op.index)', function(allDone) {95 async.series([96 this.doc.create.bind(this.doc, [ 'a' ], typeName),97 this.doc.subscribe.bind(this.doc),98 this.doc2.subscribe.bind(this.doc2),99 this.doc.submitOp.bind(this.doc, { index: 1, value: 'b' }),100 this.doc.submitOp.bind(this.doc, { index: 2, value: 'c' }),101 function(done) {102 this.doc2.on('presence', function(srcList, submitted) {103 expect(srcList).to.eql([ this.connection.id ]);104 expect(submitted).to.equal(true);105 expect(this.doc2.data).to.eql([ 'a', 'b', 'c' ]);106 expect(this.doc2.presence[this.connection.id]).to.eql(p(0));107 done();108 }.bind(this));109 // A hack to send presence for an older version.110 this.doc.version = 1;111 this.doc.data = [ 'a' ];112 this.doc.requestReplyPresence = false;113 this.doc.submitPresence(p(0), errorHandler(done));114 }.bind(this)115 ], allDone);116 });117 it('handles presence sent for earlier revisions (own ops, presence.index === op.index)', function(allDone) {118 async.series([119 this.doc.create.bind(this.doc, [ 'a' ], typeName),120 this.doc.subscribe.bind(this.doc),121 this.doc2.subscribe.bind(this.doc2),122 this.doc.submitOp.bind(this.doc, { index: 1, value: 'c' }),123 this.doc.submitOp.bind(this.doc, { index: 1, value: 'b' }),124 function(done) {125 this.doc2.on('presence', function(srcList, submitted) {126 expect(srcList).to.eql([ this.connection.id ]);127 expect(submitted).to.equal(true);128 expect(this.doc2.data).to.eql([ 'a', 'b', 'c' ]);129 expect(this.doc2.presence[this.connection.id]).to.eql(p(3));130 done();131 }.bind(this));132 // A hack to send presence for an older version.133 this.doc.version = 1;134 this.doc.data = [ 'a' ];135 this.doc.requestReplyPresence = false;136 this.doc.submitPresence(p(1), errorHandler(done));137 }.bind(this)138 ], allDone);139 });140 it('handles presence sent for earlier revisions (own ops, presence.index > op.index)', function(allDone) {141 async.series([142 this.doc.create.bind(this.doc, [ 'c' ], typeName),143 this.doc.subscribe.bind(this.doc),144 this.doc2.subscribe.bind(this.doc2),145 this.doc.submitOp.bind(this.doc, { index: 0, value: 'b' }),146 this.doc.submitOp.bind(this.doc, { index: 0, value: 'a' }),147 function(done) {148 this.doc2.on('presence', function(srcList, submitted) {149 expect(srcList).to.eql([ this.connection.id ]);150 expect(submitted).to.equal(true);151 expect(this.doc2.data).to.eql([ 'a', 'b', 'c' ]);152 expect(this.doc2.presence[this.connection.id]).to.eql(p(3));153 done();154 }.bind(this));155 // A hack to send presence for an older version.156 this.doc.version = 1;157 this.doc.data = [ 'c' ];158 this.doc.requestReplyPresence = false;159 this.doc.submitPresence(p(1), errorHandler(done));160 }.bind(this)161 ], allDone);162 });163 it('handles presence sent for earlier revisions (non-own ops, presence.index < op.index)', function(allDone) {164 async.series([165 this.doc.create.bind(this.doc, [ 'a' ], typeName),166 this.doc.subscribe.bind(this.doc),167 this.doc2.subscribe.bind(this.doc2),168 this.doc2.submitOp.bind(this.doc2, { index: 1, value: 'b' }),169 this.doc2.submitOp.bind(this.doc2, { index: 2, value: 'c' }),170 function(done) {171 this.doc2.on('presence', function(srcList, submitted) {172 expect(srcList).to.eql([ this.connection.id ]);173 expect(submitted).to.equal(true);174 expect(this.doc2.data).to.eql([ 'a', 'b', 'c' ]);175 expect(this.doc2.presence[this.connection.id]).to.eql(p(0));176 done();177 }.bind(this));178 // A hack to send presence for an older version.179 this.doc.version = 1;180 this.doc.data = [ 'a' ];181 this.doc.requestReplyPresence = false;182 this.doc.submitPresence(p(0), errorHandler(done));183 }.bind(this)184 ], allDone);185 });186 it('handles presence sent for earlier revisions (non-own ops, presence.index === op.index)', function(allDone) {187 async.series([188 this.doc.create.bind(this.doc, [ 'a' ], typeName),189 this.doc.subscribe.bind(this.doc),190 this.doc2.subscribe.bind(this.doc2),191 this.doc2.submitOp.bind(this.doc2, { index: 1, value: 'c' }),192 this.doc2.submitOp.bind(this.doc2, { index: 1, value: 'b' }),193 function(done) {194 this.doc2.on('presence', function(srcList, submitted) {195 expect(srcList).to.eql([ this.connection.id ]);196 expect(submitted).to.equal(true);197 expect(this.doc2.data).to.eql([ 'a', 'b', 'c' ]);198 expect(this.doc2.presence[this.connection.id]).to.eql(p(1));199 done();200 }.bind(this));201 // A hack to send presence for an older version.202 this.doc.version = 1;203 this.doc.data = [ 'a' ];204 this.doc.requestReplyPresence = false;205 this.doc.submitPresence(p(1), errorHandler(done));206 }.bind(this)207 ], allDone);208 });209 it('handles presence sent for earlier revisions (non-own ops, presence.index > op.index)', function(allDone) {210 async.series([211 this.doc.create.bind(this.doc, [ 'c' ], typeName),212 this.doc.subscribe.bind(this.doc),213 this.doc2.subscribe.bind(this.doc2),214 this.doc2.submitOp.bind(this.doc2, { index: 0, value: 'b' }),215 this.doc2.submitOp.bind(this.doc2, { index: 0, value: 'a' }),216 function(done) {217 this.doc2.on('presence', function(srcList, submitted) {218 expect(srcList).to.eql([ this.connection.id ]);219 expect(submitted).to.equal(true);220 expect(this.doc2.data).to.eql([ 'a', 'b', 'c' ]);221 expect(this.doc2.presence[this.connection.id]).to.eql(p(3));222 done();223 }.bind(this));224 // A hack to send presence for an older version.225 this.doc.version = 1;226 this.doc.data = [ 'c' ];227 this.doc.requestReplyPresence = false;228 this.doc.submitPresence(p(1), errorHandler(done));229 }.bind(this)230 ], allDone);231 });232 it('handles presence sent for earlier revisions (transform against non-op)', function(allDone) {233 async.series([234 this.doc.subscribe.bind(this.doc),235 this.doc2.subscribe.bind(this.doc2),236 this.doc.create.bind(this.doc, [], typeName),237 this.doc.submitOp.bind(this.doc, { index: 0, value: 'a' }),238 this.doc.del.bind(this.doc),239 this.doc.create.bind(this.doc, [ 'b' ], typeName),240 function(done) {241 this.doc2.once('presence', function(srcList, submitted) {242 expect(srcList).to.eql([ this.connection.id ]);243 expect(submitted).to.equal(true);244 expect(this.doc2.data).to.eql([ 'b' ]);245 expect(this.doc2.presence[this.connection.id]).to.eql(p(0));246 done();247 }.bind(this));248 this.doc.requestReplyPresence = false;249 this.doc.submitPresence(p(0), errorHandler(done));250 }.bind(this),251 function(done) {252 this.doc2.on('presence', function(srcList, submitted) {253 expect(srcList).to.eql([ this.connection.id ]);254 expect(submitted).to.equal(true);255 expect(this.doc2.data).to.eql([ 'b' ]);256 expect(this.doc2.presence).to.not.have.key(this.connection.id);257 done();258 }.bind(this));259 // A hack to send presence for an older version.260 this.doc.version = 2;261 this.doc.requestReplyPresence = false;262 this.doc.submitPresence(p(1), errorHandler(done));263 }.bind(this)264 ], allDone);265 });266 it('handles presence sent for earlier revisions (no cached ops)', function(allDone) {267 async.series([268 this.doc.create.bind(this.doc, [ 'a' ], typeName),269 this.doc.subscribe.bind(this.doc),270 this.doc2.subscribe.bind(this.doc2),271 this.doc.submitOp.bind(this.doc, { index: 1, value: 'b' }),272 this.doc.submitOp.bind(this.doc, { index: 2, value: 'c' }),273 function(done) {274 this.doc2.once('presence', function(srcList, submitted) {275 expect(srcList).to.eql([ this.connection.id ]);276 expect(submitted).to.equal(true);277 expect(this.doc2.data).to.eql([ 'a', 'b', 'c' ]);278 expect(this.doc2.presence[this.connection.id]).to.eql(p(0));279 done();280 }.bind(this));281 this.doc.requestReplyPresence = false;282 this.doc.submitPresence(p(0), errorHandler(done));283 }.bind(this),284 function(done) {285 this.doc2.cachedOps = [];286 this.doc2.on('presence', function(srcList, submitted) {287 expect(srcList).to.eql([ this.connection.id ]);288 expect(submitted).to.equal(true);289 expect(this.doc2.data).to.eql([ 'a', 'b', 'c' ]);290 expect(this.doc2.presence).to.not.have.key(this.connection.id);291 done();292 }.bind(this));293 // A hack to send presence for an older version.294 this.doc.version = 1;295 this.doc.data = [ 'a' ];296 this.doc.requestReplyPresence = false;297 this.doc.submitPresence(p(1), errorHandler(done));298 }.bind(this)299 ], allDone);300 });301 it('transforms presence against local delete', function(allDone) {302 async.series([303 this.doc.create.bind(this.doc, [], typeName),304 this.doc.subscribe.bind(this.doc),305 this.doc2.subscribe.bind(this.doc2),306 this.doc.submitPresence.bind(this.doc, p(0)),307 this.doc2.submitPresence.bind(this.doc2, p(0)),308 setTimeout,309 function(done) {310 this.doc.on('presence', function(srcList, submitted) {311 expect(srcList.sort()).to.eql([ '', this.connection2.id ]);312 expect(submitted).to.equal(false);313 expect(this.doc.presence).to.not.have.key('');314 expect(this.doc.presence).to.not.have.key(this.connection2.id);315 done();316 }.bind(this));317 this.doc.del(errorHandler(done));318 }.bind(this)319 ], allDone);320 });321 it('transforms presence against non-local delete', function(allDone) {322 async.series([323 this.doc.create.bind(this.doc, [], typeName),324 this.doc.subscribe.bind(this.doc),325 this.doc2.subscribe.bind(this.doc2),326 this.doc.submitPresence.bind(this.doc, p(0)),327 this.doc2.submitPresence.bind(this.doc2, p(0)),328 setTimeout,329 function(done) {330 this.doc.on('presence', function(srcList, submitted) {331 expect(srcList.sort()).to.eql([ '', this.connection2.id ]);332 expect(submitted).to.equal(false);333 expect(this.doc.presence).to.not.have.key('');334 expect(this.doc.presence).to.not.have.key(this.connection2.id);335 done();336 }.bind(this));337 this.doc2.del(errorHandler(done));338 }.bind(this)339 ], allDone);340 });341 it('transforms presence against local op (presence.index != op.index)', function(allDone) {342 async.series([343 this.doc.create.bind(this.doc, [ 'a', 'c' ], typeName),344 this.doc.subscribe.bind(this.doc),345 this.doc2.subscribe.bind(this.doc2),346 this.doc.submitPresence.bind(this.doc, p(0)),347 this.doc2.submitPresence.bind(this.doc2, p(2)),348 setTimeout,349 function(done) {350 this.doc.on('presence', function(srcList, submitted) {351 expect(srcList).to.eql([ this.connection2.id ]);352 expect(submitted).to.equal(false);353 expect(this.doc.presence['']).to.eql(p(0));354 expect(this.doc.presence[this.connection2.id]).to.eql(p(3));355 done();356 }.bind(this));357 this.doc.submitOp({ index: 1, value: 'b' }, errorHandler(done));358 }.bind(this)359 ], allDone);360 });361 it('transforms presence against non-local op (presence.index != op.index)', function(allDone) {362 async.series([363 this.doc.create.bind(this.doc, [ 'a', 'c' ], typeName),364 this.doc.subscribe.bind(this.doc),365 this.doc2.subscribe.bind(this.doc2),366 this.doc.submitPresence.bind(this.doc, p(0)),367 this.doc2.submitPresence.bind(this.doc2, p(2)),368 setTimeout,369 function(done) {370 this.doc.on('presence', function(srcList, submitted) {371 expect(srcList).to.eql([ this.connection2.id ]);372 expect(submitted).to.equal(false);373 expect(this.doc.presence['']).to.eql(p(0));374 expect(this.doc.presence[this.connection2.id]).to.eql(p(3));375 done();376 }.bind(this));377 this.doc2.submitOp({ index: 1, value: 'b' }, errorHandler(done));378 }.bind(this)379 ], allDone);380 });381 it('transforms presence against local op (presence.index == op.index)', function(allDone) {382 async.series([383 this.doc.create.bind(this.doc, [ 'a', 'c' ], typeName),384 this.doc.subscribe.bind(this.doc),385 this.doc2.subscribe.bind(this.doc2),386 this.doc.submitPresence.bind(this.doc, p(1)),387 this.doc2.submitPresence.bind(this.doc2, p(1)),388 setTimeout,389 function(done) {390 this.doc.on('presence', function(srcList, submitted) {391 expect(srcList).to.eql([ '' ]);392 expect(submitted).to.equal(false);393 expect(this.doc.presence['']).to.eql(p(2));394 expect(this.doc.presence[this.connection2.id]).to.eql(p(1));395 done();396 }.bind(this));397 this.doc.submitOp({ index: 1, value: 'b' }, errorHandler(done));398 }.bind(this)399 ], allDone);400 });401 it('transforms presence against non-local op (presence.index == op.index)', function(allDone) {402 async.series([403 this.doc.create.bind(this.doc, [ 'a', 'c' ], typeName),404 this.doc.subscribe.bind(this.doc),405 this.doc2.subscribe.bind(this.doc2),406 this.doc.submitPresence.bind(this.doc, p(1)),407 this.doc2.submitPresence.bind(this.doc2, p(1)),408 setTimeout,409 function(done) {410 this.doc.on('presence', function(srcList, submitted) {411 expect(srcList).to.eql([ this.connection2.id ]);412 expect(submitted).to.equal(false);413 expect(this.doc.presence['']).to.eql(p(1));414 expect(this.doc.presence[this.connection2.id]).to.eql(p(2));415 done();416 }.bind(this));417 this.doc2.submitOp({ index: 1, value: 'b' }, errorHandler(done));418 }.bind(this)419 ], allDone);420 });421 it('caches local ops', function(allDone) {422 var op = { index: 1, value: 'b' };423 async.series([424 this.doc.create.bind(this.doc, [ 'a' ], typeName),425 this.doc.submitOp.bind(this.doc, op),426 this.doc.del.bind(this.doc),427 function(done) {428 expect(this.doc.cachedOps.length).to.equal(3);429 expect(this.doc.cachedOps[0].create).to.equal(true);430 expect(this.doc.cachedOps[1].op).to.equal(op);431 expect(this.doc.cachedOps[2].del).to.equal(true);432 done();433 }.bind(this)434 ], allDone);435 });436 it('caches non-local ops', function(allDone) {437 var op = { index: 1, value: 'b' };438 async.series([439 this.doc2.subscribe.bind(this.doc2),440 this.doc.create.bind(this.doc, [ 'a' ], typeName),441 this.doc.submitOp.bind(this.doc, op),442 this.doc.del.bind(this.doc),443 setTimeout,444 function(done) {445 expect(this.doc2.cachedOps.length).to.equal(3);446 expect(this.doc2.cachedOps[0].create).to.equal(true);447 expect(this.doc2.cachedOps[1].op).to.eql(op);448 expect(this.doc2.cachedOps[2].del).to.equal(true);449 done();450 }.bind(this)451 ], allDone);452 });453 it('expires cached ops', function(allDone) {454 var op1 = { index: 1, value: 'b' };455 var op2 = { index: 2, value: 'b' };456 var op3 = { index: 3, value: 'b' };457 this.doc.cachedOpsTimeout = 60;458 async.series([459 // Cache 2 ops.460 this.doc.create.bind(this.doc, [ 'a' ], typeName),461 this.doc.submitOp.bind(this.doc, op1),462 function(done) {463 expect(this.doc.cachedOps.length).to.equal(2);464 expect(this.doc.cachedOps[0].create).to.equal(true);465 expect(this.doc.cachedOps[1].op).to.equal(op1);466 done();467 }.bind(this),468 // Cache another op before the first 2 expire.469 function (callback) {470 setTimeout(callback, 30);471 },472 this.doc.submitOp.bind(this.doc, op2),473 function(done) {474 expect(this.doc.cachedOps.length).to.equal(3);475 expect(this.doc.cachedOps[0].create).to.equal(true);476 expect(this.doc.cachedOps[1].op).to.equal(op1);477 expect(this.doc.cachedOps[2].op).to.equal(op2);478 done();479 }.bind(this),480 // Cache another op after the first 2 expire.481 function (callback) {482 setTimeout(callback, 31);483 },484 this.doc.submitOp.bind(this.doc, op3),485 function(done) {486 expect(this.doc.cachedOps.length).to.equal(2);487 expect(this.doc.cachedOps[0].op).to.equal(op2);488 expect(this.doc.cachedOps[1].op).to.equal(op3);489 done();490 }.bind(this)491 ], allDone);492 });493 it('requests reply presence when sending presence for the first time', function(allDone) {494 async.series([495 this.doc.create.bind(this.doc, [ 'a' ], typeName),496 this.doc.subscribe.bind(this.doc),497 this.doc.submitPresence.bind(this.doc, p(0)),498 this.doc2.subscribe.bind(this.doc2),499 function(done) {500 this.doc2.on('presence', function(srcList, submitted) {501 if (srcList[0] === '') {502 expect(srcList).to.eql([ '' ]);503 expect(submitted).to.equal(true);504 expect(this.doc2.presence['']).to.eql(p(1));505 expect(this.doc2.presence).to.not.have.key(this.connection.id);506 } else {507 expect(srcList).to.eql([ this.connection.id ]);508 expect(this.doc2.presence['']).to.eql(p(1));509 expect(this.doc2.presence[this.connection.id]).to.eql(p(0));510 expect(this.doc2.requestReplyPresence).to.equal(false);511 done();512 }513 }.bind(this));514 this.doc2.submitPresence(p(1), errorHandler(done));515 }.bind(this)516 ], allDone);517 });518 it('fails to submit presence for uncreated document: callback(err)', function(allDone) {519 async.series([520 this.doc.subscribe.bind(this.doc),521 function(done) {522 this.doc.submitPresence(p(0), function(err) {523 expect(err).to.be.an(Error);524 expect(err.code).to.equal(4015);525 done();526 });527 }.bind(this)528 ], allDone);529 });530 it('fails to submit presence for uncreated document: emit(err)', function(allDone) {531 async.series([532 this.doc.subscribe.bind(this.doc),533 function(done) {534 this.doc.on('error', function(err) {535 expect(err).to.be.an(Error);536 expect(err.code).to.equal(4015);537 done();538 });539 this.doc.submitPresence(p(0));540 }.bind(this)541 ], allDone);542 });543 it('fails to submit presence, if type does not support presence: callback(err)', function(allDone) {544 async.series([545 this.doc.create.bind(this.doc, {}),546 this.doc.subscribe.bind(this.doc),547 function(done) {548 this.doc.submitPresence(p(0), function(err) {549 expect(err).to.be.an(Error);550 expect(err.code).to.equal(4029);551 done();552 });553 }.bind(this)554 ], allDone);555 });556 it('fails to submit presence, if type does not support presence: emit(err)', function(allDone) {557 async.series([558 this.doc.create.bind(this.doc, {}),559 this.doc.subscribe.bind(this.doc),560 function(done) {561 this.doc.on('error', function(err) {562 expect(err).to.be.an(Error);563 expect(err.code).to.equal(4029);564 done();565 });566 this.doc.submitPresence(p(0));567 }.bind(this)568 ], allDone);569 });570 it('submits null presence', function(allDone) {571 async.series([572 this.doc.subscribe.bind(this.doc),573 this.doc.submitPresence.bind(this.doc, null)574 ], allDone);575 });576 it('sends presence once, if submitted multiple times synchronously', function(allDone) {577 async.series([578 this.doc.create.bind(this.doc, [ 'a' ], typeName),579 this.doc.subscribe.bind(this.doc),580 this.doc2.subscribe.bind(this.doc2),581 function(done) {582 this.doc2.on('presence', function(srcList, submitted) {583 expect(srcList).to.eql([ this.connection.id ]);584 expect(submitted).to.equal(true);585 expect(this.doc2.presence[this.connection.id]).to.eql(p(2));586 done();587 }.bind(this));588 this.doc.requestReplyPresence = false;589 this.doc.submitPresence(p(0), errorHandler(done));590 this.doc.submitPresence(p(1), errorHandler(done));591 this.doc.submitPresence(p(2), errorHandler(done));592 }.bind(this)593 ], allDone);594 });595 it('buffers presence until subscribed', function(allDone) {596 async.series([597 this.doc.create.bind(this.doc, [ 'a' ], typeName),598 this.doc2.subscribe.bind(this.doc2),599 function(done) {600 this.doc2.on('presence', function(srcList, submitted) {601 expect(srcList).to.eql([ this.connection.id ]);602 expect(submitted).to.equal(true);603 expect(this.doc2.presence[this.connection.id]).to.eql(p(1));604 done();605 }.bind(this));606 this.doc.requestReplyPresence = false;607 this.doc.submitPresence(p(1), errorHandler(done));608 setTimeout(function() {609 this.doc.subscribe(function(err) {610 if (err) return done(err);611 expect(this.doc2.presence).to.eql({});612 }.bind(this));613 }.bind(this));614 }.bind(this)615 ], allDone);616 });617 it('buffers presence when disconnected', function(allDone) {618 async.series([619 this.doc.create.bind(this.doc, [ 'a' ], typeName),620 this.doc.subscribe.bind(this.doc),621 this.doc2.subscribe.bind(this.doc2),622 function(done) {623 this.doc2.on('presence', function(srcList, submitted) {624 expect(srcList).to.eql([ this.connection.id ]);625 expect(submitted).to.equal(true);626 expect(this.doc2.presence[this.connection.id]).to.eql(p(1));627 done();628 }.bind(this));629 this.connection.close();630 this.doc.submitPresence(p(1), errorHandler(done));631 process.nextTick(function() {632 this.backend.connect(this.connection);633 this.doc.requestReplyPresence = false;634 }.bind(this));635 }.bind(this)636 ], allDone);637 });638 it('submits presence without a callback', function(allDone) {639 async.series([640 this.doc.create.bind(this.doc, [ 'a' ], typeName),641 this.doc.subscribe.bind(this.doc),642 this.doc2.subscribe.bind(this.doc2),643 function(done) {644 this.doc2.on('presence', function(srcList, submitted) {645 expect(srcList).to.eql([ this.connection.id ]);646 expect(submitted).to.equal(true);647 expect(this.doc2.presence[this.connection.id]).to.eql(p(0));648 done();649 }.bind(this));650 this.doc.requestReplyPresence = false;651 this.doc.submitPresence(p(0));652 }.bind(this)653 ], allDone);654 });655 it('hasPending is true, if there is pending presence', function(allDone) {656 async.series([657 this.doc.create.bind(this.doc, [ 'a' ], typeName),658 this.doc.subscribe.bind(this.doc),659 function(done) {660 expect(this.doc.hasPending()).to.equal(false);661 this.doc.submitPresence(p(0));662 expect(this.doc.hasPending()).to.equal(true);663 expect(!!this.doc.pendingPresence).to.equal(true);664 expect(!!this.doc.inflightPresence).to.equal(false);665 this.doc.whenNothingPending(done);666 }.bind(this),667 function(done) {668 expect(this.doc.hasPending()).to.equal(false);669 expect(!!this.doc.pendingPresence).to.equal(false);670 expect(!!this.doc.inflightPresence).to.equal(false);671 done();672 }.bind(this)673 ], allDone);674 });675 it('hasPending is true, if there is inflight presence', function(allDone) {676 async.series([677 this.doc.create.bind(this.doc, [ 'a' ], typeName),678 this.doc.subscribe.bind(this.doc),679 function(done) {680 expect(this.doc.hasPending()).to.equal(false);681 this.doc.submitPresence(p(0));682 expect(this.doc.hasPending()).to.equal(true);683 expect(!!this.doc.pendingPresence).to.equal(true);684 expect(!!this.doc.inflightPresence).to.equal(false);685 process.nextTick(done);686 }.bind(this),687 function(done) {688 expect(this.doc.hasPending()).to.equal(true);689 expect(!!this.doc.pendingPresence).to.equal(false);690 expect(!!this.doc.inflightPresence).to.equal(true);691 this.doc.whenNothingPending(done);692 }.bind(this),693 function(done) {694 expect(this.doc.hasPending()).to.equal(false);695 expect(!!this.doc.pendingPresence).to.equal(false);696 expect(!!this.doc.inflightPresence).to.equal(false);697 done();698 }.bind(this)699 ], allDone);700 });701 it('receives presence after doc is deleted', function(allDone) {702 async.series([703 this.doc.create.bind(this.doc, [ 'a' ], typeName),704 this.doc.subscribe.bind(this.doc),705 this.doc2.subscribe.bind(this.doc2),706 this.doc.submitPresence.bind(this.doc, p(0)),707 setTimeout,708 function(done) {709 expect(this.doc2.presence[this.connection.id]).to.eql(p(0));710 this.doc2.on('presence', function(srcList, submitted) {711 expect(srcList).to.eql([ this.connection.id ]);712 // The call to `del` transforms the presence and fires the event.713 // The call to `submitPresence` does not fire the event because presence is already null.714 expect(submitted).to.equal(false);715 expect(this.doc2.presence).to.not.have.key(this.connection.id);716 done();717 }.bind(this));718 this.doc.requestReplyPresence = false;719 this.doc.submitPresence(p(1), errorHandler(done));720 this.doc2.del(errorHandler(done));721 }.bind(this)722 ], allDone);723 });724 it('clears peer presence on peer disconnection', function(allDone) {725 async.series([726 this.doc.create.bind(this.doc, [ 'a' ], typeName),727 this.doc.subscribe.bind(this.doc),728 this.doc2.subscribe.bind(this.doc2),729 this.doc.submitPresence.bind(this.doc, p(0)),730 this.doc2.submitPresence.bind(this.doc2, p(1)),731 setTimeout,732 function(done) {733 expect(this.doc.presence['']).to.eql(p(0));734 expect(this.doc.presence[this.connection2.id]).to.eql(p(1));735 expect(this.doc2.presence[this.connection.id]).to.eql(p(0));736 expect(this.doc2.presence['']).to.eql(p(1));737 var connectionId = this.connection.id;738 this.doc2.on('presence', function(srcList, submitted) {739 expect(srcList).to.eql([ connectionId ]);740 expect(submitted).to.equal(true);741 expect(this.doc2.presence).to.not.have.key(connectionId);742 expect(this.doc2.presence['']).to.eql(p(1));743 done();744 }.bind(this));745 this.connection.close();746 }.bind(this)747 ], allDone);748 });749 it('clears peer presence on own disconnection', function(allDone) {750 async.series([751 this.doc.create.bind(this.doc, [ 'a' ], typeName),752 this.doc.subscribe.bind(this.doc),753 this.doc2.subscribe.bind(this.doc2),754 this.doc.submitPresence.bind(this.doc, p(0)),755 this.doc2.submitPresence.bind(this.doc2, p(1)),756 setTimeout,757 function(done) {758 expect(this.doc.presence['']).to.eql(p(0));759 expect(this.doc.presence[this.connection2.id]).to.eql(p(1));760 expect(this.doc2.presence[this.connection.id]).to.eql(p(0));761 expect(this.doc2.presence['']).to.eql(p(1));762 var connectionId = this.connection.id;763 this.doc2.on('presence', function(srcList, submitted) {764 expect(srcList).to.eql([ connectionId ]);765 expect(submitted).to.equal(false);766 expect(this.doc2.presence).to.not.have.key(connectionId);767 expect(this.doc2.presence['']).to.eql(p(1));768 done();769 }.bind(this));770 this.connection2.close();771 }.bind(this)772 ], allDone);773 });774 it('clears peer presence on peer unsubscribe', function(allDone) {775 async.series([776 this.doc.create.bind(this.doc, [ 'a' ], typeName),777 this.doc.subscribe.bind(this.doc),778 this.doc2.subscribe.bind(this.doc2),779 this.doc.submitPresence.bind(this.doc, p(0)),780 this.doc2.submitPresence.bind(this.doc2, p(1)),781 setTimeout,782 function(done) {783 expect(this.doc.presence['']).to.eql(p(0));784 expect(this.doc.presence[this.connection2.id]).to.eql(p(1));785 expect(this.doc2.presence[this.connection.id]).to.eql(p(0));786 expect(this.doc2.presence['']).to.eql(p(1));787 var connectionId = this.connection.id;788 this.doc2.on('presence', function(srcList, submitted) {789 expect(srcList).to.eql([ connectionId ]);790 expect(submitted).to.equal(true);791 expect(this.doc2.presence).to.not.have.key(connectionId);792 expect(this.doc2.presence['']).to.eql(p(1));793 done();794 }.bind(this));795 this.doc.unsubscribe(errorHandler(done));796 }.bind(this)797 ], allDone);798 });799 it('clears peer presence on own unsubscribe', function(allDone) {800 async.series([801 this.doc.create.bind(this.doc, [ 'a' ], typeName),802 this.doc.subscribe.bind(this.doc),803 this.doc2.subscribe.bind(this.doc2),804 this.doc.submitPresence.bind(this.doc, p(0)),805 this.doc2.submitPresence.bind(this.doc2, p(1)),806 setTimeout,807 function(done) {808 expect(this.doc.presence['']).to.eql(p(0));809 expect(this.doc.presence[this.connection2.id]).to.eql(p(1));810 expect(this.doc2.presence[this.connection.id]).to.eql(p(0));811 expect(this.doc2.presence['']).to.eql(p(1));812 var connectionId = this.connection.id;813 this.doc2.on('presence', function(srcList, submitted) {814 expect(srcList).to.eql([ connectionId ]);815 expect(submitted).to.equal(false);816 expect(this.doc2.presence).to.not.have.key(connectionId);817 expect(this.doc2.presence['']).to.eql(p(1));818 done();819 }.bind(this));820 this.doc2.unsubscribe(errorHandler(done));821 }.bind(this)822 ], allDone);823 });824 it('pauses inflight and pending presence on disconnect', function(allDone) {825 async.series([826 this.doc.create.bind(this.doc, [ 'a' ], typeName),827 this.doc.subscribe.bind(this.doc),828 function(done) {829 var called = 0;830 function callback(err) {831 if (err) return done(err);832 if (++called === 2) done();833 }834 this.doc.submitPresence(p(0), callback);835 process.nextTick(function() {836 this.doc.submitPresence(p(1), callback);837 this.connection.close();838 process.nextTick(function() {839 this.backend.connect(this.connection);840 }.bind(this));841 }.bind(this));842 }.bind(this)843 ], allDone);844 });845 it('pauses inflight and pending presence on unsubscribe', function(allDone) {846 async.series([847 this.doc.create.bind(this.doc, [ 'a' ], typeName),848 this.doc.subscribe.bind(this.doc),849 function(done) {850 var called = 0;851 function callback(err) {852 if (err) return done(err);853 if (++called === 2) done();854 }855 this.doc.submitPresence(p(0), callback);856 process.nextTick(function() {857 this.doc.submitPresence(p(1), callback);858 this.doc.unsubscribe(errorHandler(done));859 process.nextTick(function() {860 this.doc.subscribe(errorHandler(done));861 }.bind(this));862 }.bind(this));863 }.bind(this)864 ], allDone);865 });866 it('re-synchronizes presence after reconnecting', function(allDone) {867 async.series([868 this.doc.create.bind(this.doc, [ 'a' ], typeName),869 this.doc.subscribe.bind(this.doc),870 this.doc2.subscribe.bind(this.doc2),871 this.doc.submitPresence.bind(this.doc, p(0)),872 this.doc2.submitPresence.bind(this.doc2, p(1)),873 setTimeout,874 function(done) {875 expect(this.doc.presence['']).to.eql(p(0));876 expect(this.doc.presence[this.connection2.id]).to.eql(p(1));877 this.connection.close();878 expect(this.doc.presence['']).to.eql(p(0));879 expect(this.doc.presence).to.not.have.key(this.connection2.id);880 this.backend.connect(this.connection);881 process.nextTick(done);882 }.bind(this),883 setTimeout, // wait for re-sync884 function(done) {885 expect(this.doc.presence['']).to.eql(p(0));886 expect(this.doc.presence[this.connection2.id]).to.eql(p(1));887 process.nextTick(done);888 }.bind(this)889 ], allDone);890 });891 it('re-synchronizes presence after resubscribing', function(allDone) {892 async.series([893 this.doc.create.bind(this.doc, [ 'a' ], typeName),894 this.doc.subscribe.bind(this.doc),895 this.doc2.subscribe.bind(this.doc2),896 this.doc.submitPresence.bind(this.doc, p(0)),897 this.doc2.submitPresence.bind(this.doc2, p(1)),898 setTimeout,899 function(done) {900 expect(this.doc.presence['']).to.eql(p(0));901 expect(this.doc.presence[this.connection2.id]).to.eql(p(1));902 this.doc.unsubscribe(errorHandler(done));903 expect(this.doc.presence['']).to.eql(p(0));904 expect(this.doc.presence).to.not.have.key(this.connection2.id);905 this.doc.subscribe(done);906 }.bind(this),907 setTimeout, // wait for re-sync908 function(done) {909 expect(this.doc.presence['']).to.eql(p(0));910 expect(this.doc.presence[this.connection2.id]).to.eql(p(1));911 process.nextTick(done);912 }.bind(this)913 ], allDone);914 });915 it('transforms received presence against inflight and pending ops (presence.index < op.index)', function(allDone) {916 async.series([917 this.doc.create.bind(this.doc, [ 'a' ], typeName),918 this.doc.subscribe.bind(this.doc),919 this.doc2.subscribe.bind(this.doc2),920 function(done) {921 this.doc2.on('presence', function(srcList, submitted) {922 expect(srcList).to.eql([ this.connection.id ]);923 expect(submitted).to.equal(true);924 expect(this.doc2.presence[this.connection.id]).to.eql(p(0));925 done();926 }.bind(this));927 this.doc.requestReplyPresence = false;928 this.doc.submitPresence(p(0), errorHandler(done));929 this.doc2.submitOp({ index: 1, value: 'b' }, errorHandler(done))930 this.doc2.submitOp({ index: 2, value: 'c' }, errorHandler(done))931 }.bind(this)932 ], allDone);933 });934 it('transforms received presence against inflight and pending ops (presence.index === op.index)', function(allDone) {935 async.series([936 this.doc.create.bind(this.doc, [ 'a' ], typeName),937 this.doc.subscribe.bind(this.doc),938 this.doc2.subscribe.bind(this.doc2),939 function(done) {940 this.doc2.on('presence', function(srcList, submitted) {941 expect(srcList).to.eql([ this.connection.id ]);942 expect(submitted).to.equal(true);943 expect(this.doc2.presence[this.connection.id]).to.eql(p(1));944 done();945 }.bind(this));946 this.doc.requestReplyPresence = false;947 this.doc.submitPresence(p(1), errorHandler(done));948 this.doc2.submitOp({ index: 1, value: 'c' }, errorHandler(done))949 this.doc2.submitOp({ index: 1, value: 'b' }, errorHandler(done))950 }.bind(this)951 ], allDone);952 });953 it('transforms received presence against inflight and pending ops (presence.index > op.index)', function(allDone) {954 async.series([955 this.doc.create.bind(this.doc, [ 'c' ], typeName),956 this.doc.subscribe.bind(this.doc),957 this.doc2.subscribe.bind(this.doc2),958 function(done) {959 this.doc2.on('presence', function(srcList, submitted) {960 expect(srcList).to.eql([ this.connection.id ]);961 expect(submitted).to.equal(true);962 expect(this.doc2.presence[this.connection.id]).to.eql(p(3));963 done();964 }.bind(this));965 this.doc.requestReplyPresence = false;966 this.doc.submitPresence(p(1), errorHandler(done));967 this.doc2.submitOp({ index: 0, value: 'b' }, errorHandler(done))968 this.doc2.submitOp({ index: 0, value: 'a' }, errorHandler(done))969 }.bind(this)970 ], allDone);971 });972 it('transforms received presence against inflight delete', function(allDone) {973 async.series([974 this.doc.create.bind(this.doc, [ 'c' ], typeName),975 this.doc.subscribe.bind(this.doc),976 this.doc2.subscribe.bind(this.doc2),977 this.doc.submitPresence.bind(this.doc, p(1)),978 setTimeout,979 function(done) {980 this.doc2.on('presence', function(srcList, submitted) {981 expect(srcList).to.eql([ this.connection.id ]);982 // The call to `del` transforms the presence and fires the event.983 // The call to `submitPresence` does not fire the event because presence is already null.984 expect(submitted).to.equal(false);985 expect(this.doc2.presence).to.not.have.key(this.connection.id);986 done();987 }.bind(this));988 this.doc.requestReplyPresence = false;989 this.doc.submitPresence(p(2), errorHandler(done));990 this.doc2.del(errorHandler(done));991 this.doc2.create([ 'c' ], typeName, errorHandler(done));992 }.bind(this)993 ], allDone);994 });995 it('transforms received presence against a pending delete', function(allDone) {996 async.series([997 this.doc.create.bind(this.doc, [ 'c' ], typeName),998 this.doc.subscribe.bind(this.doc),999 this.doc2.subscribe.bind(this.doc2),1000 this.doc.submitPresence.bind(this.doc, p(1)),1001 setTimeout,1002 function(done) {1003 var firstCall = true;1004 this.doc2.on('presence', function(srcList, submitted) {1005 if (firstCall) return firstCall = false;1006 expect(srcList).to.eql([ this.connection.id ]);1007 // The call to `del` transforms the presence and fires the event.1008 // The call to `submitPresence` does not fire the event because presence is already null.1009 expect(submitted).to.equal(false);1010 expect(this.doc2.presence).to.not.have.key(this.connection.id);1011 done();1012 }.bind(this));1013 this.doc.requestReplyPresence = false;1014 this.doc.submitPresence(p(2), errorHandler(done));1015 this.doc2.submitOp({ index: 0, value: 'b' }, errorHandler(done));1016 this.doc2.del(errorHandler(done));1017 this.doc2.create([ 'c' ], typeName, errorHandler(done));1018 }.bind(this)1019 ], allDone);1020 });1021 it('emits the same presence only if comparePresence is not implemented (local presence)', function(allDone) {1022 async.series([1023 this.doc.create.bind(this.doc, [ 'c' ], typeName),1024 this.doc.subscribe.bind(this.doc),1025 this.doc.submitPresence.bind(this.doc, p(1)),1026 function(done) {1027 this.doc.on('presence', function(srcList, submitted) {1028 if (typeName === 'wrapped-presence-no-compare') {1029 expect(srcList).to.eql([ '' ]);1030 expect(submitted).to.equal(true);1031 expect(this.doc.presence['']).to.eql(p(1));1032 done();1033 } else {1034 done(new Error('Unexpected presence event'));1035 }1036 }.bind(this));1037 this.doc.submitPresence(p(1), typeName === 'wrapped-presence-no-compare' ? errorHandler(done) : done);1038 }.bind(this)1039 ], allDone);1040 });1041 it('emits the same presence only if comparePresence is not implemented (non-local presence)', function(allDone) {1042 async.series([1043 this.doc.create.bind(this.doc, [ 'c' ], typeName),1044 this.doc.subscribe.bind(this.doc),1045 this.doc2.subscribe.bind(this.doc2),1046 this.doc.submitPresence.bind(this.doc, p(1)),1047 setTimeout,1048 function(done) {1049 this.doc2.on('presence', function(srcList, submitted) {1050 if (typeName === 'wrapped-presence-no-compare') {1051 expect(srcList).to.eql([ this.connection.id ]);1052 expect(submitted).to.equal(true);1053 expect(this.doc2.presence[this.connection.id]).to.eql(p(1));1054 done();1055 } else {1056 done(new Error('Unexpected presence event'));1057 }1058 }.bind(this));1059 this.doc.submitPresence(p(1), typeName === 'wrapped-presence-no-compare' ? errorHandler(done) : done);1060 }.bind(this)1061 ], allDone);1062 });1063 it('returns an error when not subscribed on the server', function(allDone) {1064 async.series([1065 this.doc.create.bind(this.doc, [ 'c' ], typeName),1066 this.doc.subscribe.bind(this.doc),1067 function(done) {1068 this.connection.sendUnsubscribe(this.doc);1069 process.nextTick(done);1070 }.bind(this),1071 function(done) {1072 this.doc.on('error', done);1073 this.doc.submitPresence(p(0), function(err) {1074 expect(err).to.be.an(Error);1075 expect(err.code).to.equal(4025);1076 done();1077 }.bind(this));1078 }.bind(this)1079 ], allDone);1080 });1081 it('emits an error when not subscribed on the server and no callback is provided', function(allDone) {1082 async.series([1083 this.doc.create.bind(this.doc, [ 'c' ], typeName),1084 this.doc.subscribe.bind(this.doc),1085 function(done) {1086 this.connection.sendUnsubscribe(this.doc);1087 process.nextTick(done);1088 }.bind(this),1089 function(done) {1090 this.doc.on('error', function(err) {1091 expect(err).to.be.an(Error);1092 expect(err.code).to.equal(4025);1093 done();1094 }.bind(this));1095 this.doc.submitPresence(p(0));1096 }.bind(this)1097 ], allDone);1098 });1099 it('returns an error when the server gets an old sequence number', function(allDone) {1100 async.series([1101 this.doc.create.bind(this.doc, [ 'c' ], typeName),1102 this.doc.subscribe.bind(this.doc),1103 this.doc.submitPresence.bind(this.doc, p(0)),1104 setTimeout,1105 function(done) {1106 this.doc.on('error', done);1107 this.connection.seq--;1108 this.doc.submitPresence(p(1), function(err) {1109 expect(err).to.be.an(Error);1110 expect(err.code).to.equal(4026);1111 done();1112 }.bind(this));1113 }.bind(this)1114 ], allDone);1115 });1116 it('emits an error when the server gets an old sequence number and no callback is provided', function(allDone) {1117 async.series([1118 this.doc.create.bind(this.doc, [ 'c' ], typeName),1119 this.doc.subscribe.bind(this.doc),1120 this.doc.submitPresence.bind(this.doc, p(0)),1121 setTimeout,1122 function(done) {1123 this.doc.on('error', function(err) {1124 expect(err).to.be.an(Error);1125 expect(err.code).to.equal(4026);1126 done();1127 }.bind(this));1128 this.connection.seq--;1129 this.doc.submitPresence(p(1));1130 }.bind(this)1131 ], allDone);1132 });1133 it('does not publish presence unnecessarily', function(allDone) {1134 async.series([1135 this.doc.create.bind(this.doc, [ 'c' ], typeName),1136 this.doc.subscribe.bind(this.doc),1137 this.doc.submitPresence.bind(this.doc, p(0)),1138 setTimeout,1139 function(done) {1140 this.doc.on('error', done);1141 // Decremented sequence number would cause the server to return an error, however,1142 // the message won't be sent to the server at all because the presence data has not changed.1143 this.connection.seq--;1144 this.doc.submitPresence(p(0), function(err) {1145 if (typeName === 'wrapped-presence-no-compare') {1146 // The OT type does not support comparing presence.1147 expect(err).to.be.an(Error);1148 expect(err.code).to.equal(4026);1149 } else {1150 expect(err).to.not.be.ok();1151 }1152 done();1153 }.bind(this));1154 }.bind(this)1155 ], allDone);1156 });1157 it('does not publish presence unnecessarily when no callback is provided', function(allDone) {1158 async.series([1159 this.doc.create.bind(this.doc, [ 'c' ], typeName),1160 this.doc.subscribe.bind(this.doc),1161 this.doc.submitPresence.bind(this.doc, p(0)),1162 setTimeout,1163 function(done) {1164 this.doc.on('error', function(err) {1165 if (typeName === 'wrapped-presence-no-compare') {1166 // The OT type does not support comparing presence.1167 expect(err).to.be.an(Error);1168 expect(err.code).to.equal(4026);1169 done();1170 } else {1171 done(err);1172 }1173 }.bind(this));1174 // Decremented sequence number would cause the server to return an error, however,1175 // the message won't be sent to the server at all because the presence data has not changed.1176 this.connection.seq--;1177 this.doc.submitPresence(p(0));1178 if (typeName !== 'wrapped-presence-no-compare') {1179 process.nextTick(done);1180 }1181 }.bind(this)1182 ], allDone);1183 });1184 it('returns an error when publishing presence fails', function(allDone) {1185 async.series([1186 this.doc.create.bind(this.doc, [ 'c' ], typeName),1187 this.doc.subscribe.bind(this.doc),1188 setTimeout,1189 function(done) {1190 var sendPresence = this.backend.sendPresence;1191 this.backend.sendPresence = function(presence, callback) {1192 if (presence.a === 'p' && presence.v != null) {1193 return callback(new ShareDBError(-1, 'Test publishing error'));1194 }1195 sendPresence.apply(this, arguments);1196 };1197 this.doc.on('error', done);1198 this.doc.submitPresence(p(0), function(err) {1199 expect(err).to.be.an(Error);1200 expect(err.code).to.equal(-1);1201 done();1202 }.bind(this));1203 }.bind(this)1204 ], allDone);1205 });1206 it('emits an error when publishing presence fails and no callback is provided', function(allDone) {1207 async.series([1208 this.doc.create.bind(this.doc, [ 'c' ], typeName),1209 this.doc.subscribe.bind(this.doc),1210 setTimeout,1211 function(done) {1212 var sendPresence = this.backend.sendPresence;1213 this.backend.sendPresence = function(presence, callback) {1214 if (presence.a === 'p' && presence.v != null) {1215 return callback(new ShareDBError(-1, 'Test publishing error'));1216 }1217 sendPresence.apply(this, arguments);1218 };1219 this.doc.on('error', function(err) {1220 expect(err).to.be.an(Error);1221 expect(err.code).to.equal(-1);1222 done();1223 }.bind(this));1224 this.doc.submitPresence(p(0));1225 }.bind(this)1226 ], allDone);1227 });1228 it('clears presence on hard rollback and emits an error', function(allDone) {1229 async.series([1230 this.doc.create.bind(this.doc, [ 'a', 'b', 'c' ], typeName),1231 this.doc.subscribe.bind(this.doc),1232 this.doc2.subscribe.bind(this.doc2),1233 this.doc.submitPresence.bind(this.doc, p(0)),1234 this.doc2.submitPresence.bind(this.doc2, p(0)),1235 setTimeout,1236 function(done) {1237 // A hack to allow testing of hard rollback of both inflight and pending presence.1238 var doc = this.doc;1239 var _handlePresence = this.doc._handlePresence;1240 this.doc._handlePresence = function(err, presence) {1241 setTimeout(function() {1242 _handlePresence.call(doc, err, presence);1243 });1244 };1245 process.nextTick(done);1246 }.bind(this),1247 this.doc.submitPresence.bind(this.doc, p(1)), // inflightPresence1248 process.nextTick, // wait for "presence" event1249 this.doc.submitPresence.bind(this.doc, p(2)), // pendingPresence1250 process.nextTick, // wait for "presence" event1251 function(done) {1252 var presenceEmitted = false;1253 this.doc.on('presence', function(srcList, submitted) {1254 expect(presenceEmitted).to.equal(false);1255 presenceEmitted = true;1256 expect(srcList.sort()).to.eql([ '', this.connection2.id ]);1257 expect(submitted).to.equal(false);1258 expect(this.doc.presence).to.not.have.key('');1259 expect(this.doc.presence).to.not.have.key(this.connection2.id);1260 }.bind(this));1261 this.doc.on('error', function(err) {1262 expect(presenceEmitted).to.equal(true);1263 expect(err).to.be.an(Error);1264 expect(err.code).to.equal(4000);1265 done();1266 }.bind(this));1267 // send an invalid op1268 this.doc._submit({}, null);1269 }.bind(this)1270 ], allDone);1271 });1272 it('clears presence on hard rollback and executes all callbacks', function(allDone) {1273 async.series([1274 this.doc.create.bind(this.doc, [ 'a', 'b', 'c' ], typeName),1275 this.doc.subscribe.bind(this.doc),1276 this.doc2.subscribe.bind(this.doc2),1277 this.doc.submitPresence.bind(this.doc, p(0)),1278 this.doc2.submitPresence.bind(this.doc2, p(0)),1279 setTimeout,1280 function(done) {1281 // A hack to allow testing of hard rollback of both inflight and pending presence.1282 var doc = this.doc;1283 var _handlePresence = this.doc._handlePresence;1284 this.doc._handlePresence = function(err, presence) {1285 setTimeout(function() {1286 _handlePresence.call(doc, err, presence);1287 });1288 };1289 process.nextTick(done);1290 }.bind(this),1291 function(done) {1292 var presenceEmitted = false;1293 var called = 0;1294 function callback(err) {1295 expect(presenceEmitted).to.equal(true);1296 expect(err).to.be.an(Error);1297 expect(err.code).to.equal(4000);1298 if (++called < 3) return;1299 done();1300 }1301 this.doc.submitPresence(p(1), callback); // inflightPresence1302 process.nextTick(function() { // wait for presence event1303 this.doc.submitPresence(p(2), callback); // pendingPresence1304 process.nextTick(function() { // wait for presence event1305 this.doc.on('presence', function(srcList, submitted) {1306 expect(presenceEmitted).to.equal(false);1307 presenceEmitted = true;1308 expect(srcList.sort()).to.eql([ '', this.connection2.id ]);1309 expect(submitted).to.equal(false);1310 expect(this.doc.presence).to.not.have.key('');1311 expect(this.doc.presence).to.not.have.key(this.connection2.id);1312 }.bind(this));1313 this.doc.on('error', done);1314 // send an invalid op1315 this.doc._submit({ index: 3, value: 'b' }, null, callback);1316 }.bind(this));1317 }.bind(this));1318 }.bind(this)1319 ], allDone);1320 });1321 function testReceivedMessageExpiry(expireCache, reduceSequence) {1322 return function(allDone) {1323 var lastPresence = null;1324 var handleMessage = this.connection.handleMessage;1325 this.connection.handleMessage = function(message) {1326 if (message.a === 'p' && message.src) {1327 lastPresence = JSON.parse(JSON.stringify(message));1328 }1329 return handleMessage.apply(this, arguments);1330 };1331 if (expireCache) {1332 this.doc.receivedPresenceTimeout = 0;1333 }1334 async.series([1335 this.doc.create.bind(this.doc, [ 'a' ], typeName),1336 this.doc.subscribe.bind(this.doc),1337 this.doc2.subscribe.bind(this.doc2),1338 function(done) {1339 this.doc2.requestReplyPresence = false;1340 this.doc2.submitPresence(p(0), done);1341 }.bind(this),1342 setTimeout,1343 this.doc2.submitOp.bind(this.doc2, { index: 1, value: 'b' }), // forces processing of all received presence1344 setTimeout,1345 function(done) {1346 expect(this.doc.data).to.eql([ 'a', 'b' ]);1347 expect(this.doc.presence[this.connection2.id]).to.eql(p(0));1348 // Replay the `lastPresence` with modified payload.1349 lastPresence.p = p(1);1350 lastPresence.v++; // +1 to account for the op above1351 if (reduceSequence) {1352 lastPresence.seq--;1353 }1354 this.connection.handleMessage(lastPresence);1355 process.nextTick(done);1356 }.bind(this),1357 function(done) {1358 expect(this.doc.presence[this.connection2.id]).to.eql(expireCache ? p(1) : p(0));1359 process.nextTick(done);1360 }.bind(this)1361 ], allDone);1362 };1363 }1364 it('ignores an old message (cache not expired, presence.seq === cachedPresence.seq)', testReceivedMessageExpiry(false, false));1365 it('ignores an old message (cache not expired, presence.seq < cachedPresence.seq)', testReceivedMessageExpiry(false, true));1366 it('processes an old message (cache expired, presence.seq === cachedPresence.seq)', testReceivedMessageExpiry(true, false));1367 it('processes an old message (cache expired, presence.seq < cachedPresence.seq)', testReceivedMessageExpiry(true, true));1368 });...

Full Screen

Full Screen

subscribe.js

Source:subscribe.js Github

copy

Full Screen

1var expect = require('expect.js');2var async = require('async');3module.exports = function() {4describe('client subscribe', function() {5 it('can call bulk without doing any actions', function() {6 var connection = this.backend.connect();7 connection.startBulk();8 connection.endBulk();9 });10 ['fetch', 'subscribe'].forEach(function(method) {11 it(method + ' gets initial data', function(done) {12 var doc = this.backend.connect().get('dogs', 'fido');13 var doc2 = this.backend.connect().get('dogs', 'fido');14 doc.create({age: 3}, function(err) {15 if (err) return done(err);16 doc2[method](function(err) {17 if (err) return done(err);18 expect(doc2.version).eql(1);19 expect(doc2.data).eql({age: 3});20 done();21 });22 });23 });24 it(method + ' twice simultaneously calls back', function(done) {25 var doc = this.backend.connect().get('dogs', 'fido');26 var doc2 = this.backend.connect().get('dogs', 'fido');27 doc.create({age: 3}, function(err) {28 if (err) return done(err);29 async.parallel([30 function(cb) { doc2[method](cb); },31 function(cb) { doc2[method](cb); }32 ], function(err) {33 if (err) return done(err);34 expect(doc2.version).eql(1);35 expect(doc2.data).eql({age: 3});36 done();37 });38 });39 });40 it(method + ' twice in bulk simultaneously calls back', function(done) {41 var doc = this.backend.connect().get('dogs', 'fido');42 var doc2 = this.backend.connect().get('dogs', 'fido');43 doc.create({age: 3}, function(err) {44 if (err) return done(err);45 doc2.connection.startBulk();46 async.parallel([47 function(cb) { doc2[method](cb); },48 function(cb) { doc2[method](cb); }49 ], function(err) {50 if (err) return done(err);51 expect(doc2.version).eql(1);52 expect(doc2.data).eql({age: 3});53 done();54 });55 doc2.connection.endBulk();56 });57 });58 it(method + ' bulk on same collection', function(done) {59 var connection = this.backend.connect();60 var connection2 = this.backend.connect();61 async.parallel([62 function(cb) { connection.get('dogs', 'fido').create({age: 3}, cb); },63 function(cb) { connection.get('dogs', 'spot').create({age: 5}, cb); },64 function(cb) { connection.get('cats', 'finn').create({age: 2}, cb); }65 ], function(err) {66 if (err) return done(err);67 var fido = connection2.get('dogs', 'fido');68 var spot = connection2.get('dogs', 'spot');69 var finn = connection2.get('cats', 'finn');70 connection2.startBulk();71 async.parallel([72 function(cb) { fido[method](cb); },73 function(cb) { spot[method](cb); },74 function(cb) { finn[method](cb); }75 ], function(err) {76 if (err) return done(err);77 expect(fido.data).eql({age: 3});78 expect(spot.data).eql({age: 5});79 expect(finn.data).eql({age: 2});80 done();81 });82 connection2.endBulk();83 });84 });85 it(method + ' bulk on same collection from known version', function(done) {86 var connection = this.backend.connect();87 var connection2 = this.backend.connect();88 var fido = connection2.get('dogs', 'fido');89 var spot = connection2.get('dogs', 'spot');90 var finn = connection2.get('cats', 'finn');91 connection2.startBulk();92 async.parallel([93 function(cb) { fido[method](cb); },94 function(cb) { spot[method](cb); },95 function(cb) { finn[method](cb); }96 ], function(err) {97 if (err) return done(err);98 expect(fido.version).equal(0);99 expect(spot.version).equal(0);100 expect(finn.version).equal(0);101 expect(fido.data).equal(undefined);102 expect(spot.data).equal(undefined);103 expect(finn.data).equal(undefined);104 async.parallel([105 function(cb) { connection.get('dogs', 'fido').create({age: 3}, cb); },106 function(cb) { connection.get('dogs', 'spot').create({age: 5}, cb); },107 function(cb) { connection.get('cats', 'finn').create({age: 2}, cb); }108 ], function(err) {109 if (err) return done(err);110 connection2.startBulk();111 async.parallel([112 function(cb) { fido[method](cb); },113 function(cb) { spot[method](cb); },114 function(cb) { finn[method](cb); }115 ], function(err) {116 if (err) return done(err);117 expect(fido.data).eql({age: 3});118 expect(spot.data).eql({age: 5});119 expect(finn.data).eql({age: 2});120 // Test sending a fetch without any new ops being created121 connection2.startBulk();122 async.parallel([123 function(cb) { fido[method](cb); },124 function(cb) { spot[method](cb); },125 function(cb) { finn[method](cb); }126 ], function(err) {127 if (err) return done(err);128 // Create new ops and test if they are received129 async.parallel([130 function(cb) { connection.get('dogs', 'fido').submitOp([{p: ['age'], na: 1}], cb); },131 function(cb) { connection.get('dogs', 'spot').submitOp([{p: ['age'], na: 1}], cb); },132 function(cb) { connection.get('cats', 'finn').submitOp([{p: ['age'], na: 1}], cb); }133 ], function(err) {134 if (err) return done(err);135 connection2.startBulk();136 async.parallel([137 function(cb) { fido[method](cb); },138 function(cb) { spot[method](cb); },139 function(cb) { finn[method](cb); }140 ], function(err) {141 if (err) return done(err);142 expect(fido.data).eql({age: 4});143 expect(spot.data).eql({age: 6});144 expect(finn.data).eql({age: 3});145 done();146 });147 connection2.endBulk();148 });149 });150 connection2.endBulk();151 });152 connection2.endBulk();153 });154 });155 connection2.endBulk();156 });157 it(method + ' gets new ops', function(done) {158 var doc = this.backend.connect().get('dogs', 'fido');159 var doc2 = this.backend.connect().get('dogs', 'fido');160 doc.create({age: 3}, function(err) {161 if (err) return done(err);162 doc2.fetch(function(err) {163 if (err) return done(err);164 doc.submitOp({p: ['age'], na: 1}, function(err) {165 if (err) return done(err);166 doc2.on('op', function(op, context) {167 done();168 });169 doc2[method]();170 });171 });172 });173 });174 it(method + ' calls back after reconnect', function(done) {175 var backend = this.backend;176 var doc = this.backend.connect().get('dogs', 'fido');177 var doc2 = this.backend.connect().get('dogs', 'fido');178 doc.create({age: 3}, function(err) {179 if (err) return done(err);180 doc2[method](function(err) {181 if (err) return done(err);182 expect(doc2.version).eql(1);183 expect(doc2.data).eql({age: 3});184 done();185 });186 doc2.connection.close();187 process.nextTick(function() {188 backend.connect(doc2.connection);189 });190 });191 });192 it(method + ' returns error passed to doc read middleware', function(done) {193 this.backend.use('doc', function(request, next) {194 next({message: 'Reject doc read'});195 });196 var doc = this.backend.connect().get('dogs', 'fido');197 var doc2 = this.backend.connect().get('dogs', 'fido');198 doc.create({age: 3}, function(err) {199 if (err) return done(err);200 doc2[method](function(err) {201 expect(err.message).equal('Reject doc read');202 expect(doc2.version).eql(null);203 expect(doc2.data).eql(undefined);204 done();205 });206 });207 });208 it(method + ' emits error passed to doc read middleware', function(done) {209 this.backend.use('doc', function(request, next) {210 next({message: 'Reject doc read'});211 });212 var doc = this.backend.connect().get('dogs', 'fido');213 var doc2 = this.backend.connect().get('dogs', 'fido');214 doc.create({age: 3}, function(err) {215 if (err) return done(err);216 doc2[method]();217 doc2.on('error', function(err) {218 expect(err.message).equal('Reject doc read');219 expect(doc2.version).eql(null);220 expect(doc2.data).eql(undefined);221 done();222 });223 });224 });225 it(method + ' emits error passed to doc read middleware after reconnect', function(done) {226 this.backend.use('doc', function(request, next) {227 next({message: 'Reject doc read'});228 });229 var backend = this.backend;230 var doc = this.backend.connect().get('dogs', 'fido');231 var doc2 = this.backend.connect().get('dogs', 'fido');232 doc.create({age: 3}, function(err) {233 if (err) return done(err);234 doc2[method]();235 doc2.on('error', function(err) {236 expect(err.message).equal('Reject doc read');237 expect(doc2.version).eql(null);238 expect(doc2.data).eql(undefined);239 done();240 });241 doc2.connection.close();242 process.nextTick(function() {243 backend.connect(doc2.connection);244 });245 });246 });247 it(method + ' will call back when ops are pending', function(done) {248 var doc = this.backend.connect().get('dogs', 'fido');249 doc.create({age: 3}, function(err) {250 if (err) return done(err);251 doc.pause();252 doc.submitOp({p: ['age'], na: 1});253 doc[method](done);254 });255 });256 it(method + ' will not call back when creating the doc is pending', function(done) {257 var doc = this.backend.connect().get('dogs', 'fido');258 doc.pause();259 doc.create({age: 3});260 doc[method](done);261 // HACK: Delay done call to keep from closing the db connection too soon262 setTimeout(done, 10);263 });264 it(method + ' will wait for write when doc is locally created', function(done) {265 var doc = this.backend.connect().get('dogs', 'fido');266 doc.pause();267 var calls = 0;268 doc.create({age: 3}, function(err) {269 if (err) return done(err);270 calls++;271 });272 doc[method](function(err) {273 if (err) return done(err);274 expect(calls).equal(1);275 expect(doc.version).equal(1);276 expect(doc.data).eql({age: 3});277 done();278 });279 setTimeout(function() {280 doc.resume();281 }, 10);282 });283 it(method + ' will wait for write when doc is locally created and will fail to submit', function(done) {284 var doc = this.backend.connect().get('dogs', 'fido');285 var doc2 = this.backend.connect().get('dogs', 'fido');286 doc2.create({age: 5}, function(err) {287 if (err) return done(err);288 doc.pause();289 var calls = 0;290 doc.create({age: 3}, function(err) {291 expect(err).ok();292 calls++;293 });294 doc[method](function(err) {295 if (err) return done(err);296 expect(calls).equal(1);297 expect(doc.version).equal(1);298 expect(doc.data).eql({age: 5});299 done();300 });301 setTimeout(function() {302 doc.resume();303 }, 10);304 });305 });306 });307 it('unsubscribe calls back immediately on disconnect', function(done) {308 var backend = this.backend;309 var doc = this.backend.connect().get('dogs', 'fido');310 doc.subscribe(function(err) {311 if (err) return done(err);312 doc.unsubscribe(done);313 doc.connection.close();314 });315 });316 it('unsubscribe calls back immediately when already disconnected', function(done) {317 var backend = this.backend;318 var doc = this.backend.connect().get('dogs', 'fido');319 doc.subscribe(function(err) {320 if (err) return done(err);321 doc.connection.close();322 doc.unsubscribe(done);323 });324 });325 it('subscribed client gets create from other client', function(done) {326 var doc = this.backend.connect().get('dogs', 'fido');327 var doc2 = this.backend.connect().get('dogs', 'fido');328 doc2.subscribe(function(err) {329 if (err) return done(err);330 doc2.on('create', function(context) {331 expect(context).equal(false);332 expect(doc2.version).eql(1);333 expect(doc2.data).eql({age: 3});334 done();335 });336 doc.create({age: 3});337 });338 });339 it('subscribed client gets op from other client', function(done) {340 var doc = this.backend.connect().get('dogs', 'fido');341 var doc2 = this.backend.connect().get('dogs', 'fido');342 doc.create({age: 3}, function(err) {343 if (err) return done(err);344 doc2.subscribe(function(err) {345 if (err) return done(err);346 doc2.on('op', function(op, context) {347 expect(doc2.version).eql(2);348 expect(doc2.data).eql({age: 4});349 done();350 });351 doc.submitOp({p: ['age'], na: 1});352 });353 });354 });355 it('disconnecting stops op updates', function(done) {356 var doc = this.backend.connect().get('dogs', 'fido');357 var doc2 = this.backend.connect().get('dogs', 'fido');358 doc.create({age: 3}, function(err) {359 if (err) return done(err);360 doc2.subscribe(function(err) {361 if (err) return done(err);362 doc2.on('op', function(op, context) {363 done();364 });365 doc2.connection.close();366 doc.submitOp({p: ['age'], na: 1}, done);367 });368 });369 });370 it('backend.suppressPublish stops op updates', function(done) {371 var backend = this.backend;372 var doc = this.backend.connect().get('dogs', 'fido');373 var doc2 = this.backend.connect().get('dogs', 'fido');374 doc.create({age: 3}, function(err) {375 if (err) return done(err);376 doc2.subscribe(function(err) {377 if (err) return done(err);378 doc2.on('op', function(op, context) {379 done();380 });381 backend.suppressPublish = true;382 doc.submitOp({p: ['age'], na: 1}, done);383 });384 });385 });386 it('unsubscribe stops op updates', function(done) {387 var doc = this.backend.connect().get('dogs', 'fido');388 var doc2 = this.backend.connect().get('dogs', 'fido');389 doc.create({age: 3}, function(err) {390 if (err) return done(err);391 doc2.subscribe(function(err) {392 if (err) return done(err);393 doc2.on('op', function(op, context) {394 done();395 });396 doc2.unsubscribe(function(err) {397 if (err) return done(err);398 doc.submitOp({p: ['age'], na: 1}, done);399 });400 });401 });402 });403 it('doc destroy stops op updates', function(done) {404 var connection1 = this.backend.connect();405 var connection2 = this.backend.connect();406 var doc = connection1.get('dogs', 'fido');407 var doc2 = connection2.get('dogs', 'fido');408 doc.create({age: 3}, function(err) {409 if (err) return done(err);410 doc2.subscribe(function(err) {411 if (err) return done(err);412 doc2.on('op', function(op, context) {413 done(new Error('Should not get op event'));414 });415 doc2.destroy(function(err) {416 if (err) return done(err);417 expect(connection2.getExisting('dogs', 'fido')).equal(undefined);418 doc.submitOp({p: ['age'], na: 1}, done);419 });420 });421 });422 });423 it('doc destroy removes doc from connection when doc is not subscribed', function(done) {424 var connection = this.backend.connect();425 var doc = connection.get('dogs', 'fido');426 expect(connection.getExisting('dogs', 'fido')).equal(doc);427 doc.destroy(function(err) {428 if (err) return done(err);429 expect(connection.getExisting('dogs', 'fido')).equal(undefined);430 done();431 });432 });433 it('bulk unsubscribe stops op updates', function(done) {434 var connection = this.backend.connect();435 var connection2 = this.backend.connect();436 var doc = connection.get('dogs', 'fido');437 var fido = connection2.get('dogs', 'fido');438 var spot = connection2.get('dogs', 'spot');439 doc.create({age: 3}, function(err) {440 if (err) return done(err);441 async.parallel([442 function(cb) { fido.subscribe(cb); },443 function(cb) { spot.subscribe(cb); }444 ], function(err) {445 if (err) return done(err);446 fido.connection.startBulk();447 async.parallel([448 function(cb) { fido.unsubscribe(cb); },449 function(cb) { spot.unsubscribe(cb); }450 ], function(err) {451 if (err) return done(err);452 fido.on('op', function(op, context) {453 done();454 });455 doc.submitOp({p: ['age'], na: 1}, done);456 });457 fido.connection.endBulk();458 });459 });460 });461 it('a subscribed doc is re-subscribed after reconnect and gets any missing ops', function(done) {462 var backend = this.backend;463 var doc = this.backend.connect().get('dogs', 'fido');464 var doc2 = this.backend.connect().get('dogs', 'fido');465 doc.create({age: 3}, function(err) {466 if (err) return done(err);467 doc2.subscribe(function(err) {468 if (err) return done(err);469 doc2.on('op', function(op, context) {470 expect(doc2.version).eql(2);471 expect(doc2.data).eql({age: 4});472 done();473 });474 doc2.connection.close();475 doc.submitOp({p: ['age'], na: 1}, function(err) {476 if (err) return done(err);477 backend.connect(doc2.connection);478 });479 });480 });481 });482 it('calling subscribe, unsubscribe, subscribe sync leaves a doc subscribed', function(done) {483 var doc = this.backend.connect().get('dogs', 'fido');484 var doc2 = this.backend.connect().get('dogs', 'fido');485 doc.create({age: 3}, function(err) {486 if (err) return done(err);487 doc2.subscribe();488 doc2.unsubscribe();489 doc2.subscribe(function(err) {490 if (err) return done(err);491 doc2.on('op', function(op, context) {492 done();493 });494 doc.submitOp({p: ['age'], na: 1});495 });496 });497 });498 it('doc fetches ops to catch up if it receives a future op', function(done) {499 var backend = this.backend;500 var doc = this.backend.connect().get('dogs', 'fido');501 var doc2 = this.backend.connect().get('dogs', 'fido');502 doc.create({age: 3}, function(err) {503 if (err) return done(err);504 doc2.subscribe(function(err) {505 if (err) return done(err);506 var expected = [507 [{p: ['age'], na: 1}],508 [{p: ['age'], na: 5}],509 ];510 doc2.on('op', function(op, context) {511 var item = expected.shift();512 expect(op).eql(item);513 if (expected.length) return;514 expect(doc2.version).equal(3);515 expect(doc2.data).eql({age: 9});516 done();517 });518 backend.suppressPublish = true;519 doc.submitOp({p: ['age'], na: 1}, function(err) {520 if (err) return done(err);521 backend.suppressPublish = false;522 doc.submitOp({p: ['age'], na: 5});523 });524 });525 });526 });527 it('doc fetches ops to catch up if it receives multiple future ops', function(done) {528 var backend = this.backend;529 var doc = this.backend.connect().get('dogs', 'fido');530 var doc2 = this.backend.connect().get('dogs', 'fido');531 // Delaying op replies will cause multiple future ops to be received532 // before the fetch to catch up completes533 backend.use('op', function(request, next) {534 setTimeout(next, 10 * Math.random());535 });536 doc.create({age: 3}, function(err) {537 if (err) return done(err);538 doc2.subscribe(function(err) {539 if (err) return done(err);540 var wait = 4;541 doc2.on('op', function(op, context) {542 if (--wait) return;543 expect(doc2.version).eql(5);544 expect(doc2.data).eql({age: 122});545 done();546 });547 backend.suppressPublish = true;548 doc.submitOp({p: ['age'], na: 1}, function(err) {549 if (err) return done(err);550 backend.suppressPublish = false;551 doc.submitOp({p: ['age'], na: 5}, function(err) {552 if (err) return done(err);553 doc.submitOp({p: ['age'], na: 13}, function(err) {554 if (err) return done(err);555 doc.submitOp({p: ['age'], na: 100});556 });557 });558 });559 });560 });561 });562 describe('doc.subscribed', function() {563 it('is set to false initially', function() {564 var doc = this.backend.connect().get('dogs', 'fido');565 expect(doc.subscribed).equal(false);566 });567 it('remains false before subscribe call completes', function() {568 var doc = this.backend.connect().get('dogs', 'fido');569 doc.subscribe();570 expect(doc.subscribed).equal(false);571 });572 it('is set to true after subscribe completes', function(done) {573 var doc = this.backend.connect().get('dogs', 'fido');574 doc.subscribe(function(err) {575 if (err) return done(err);576 expect(doc.subscribed).equal(true);577 done();578 });579 });580 it('is not set to true after subscribe completes if already unsubscribed', function(done) {581 var doc = this.backend.connect().get('dogs', 'fido');582 doc.subscribe(function(err) {583 if (err) return done(err);584 expect(doc.subscribed).equal(false);585 done();586 });587 doc.unsubscribe();588 });589 it('is set to false sychronously in unsubscribe', function(done) {590 var doc = this.backend.connect().get('dogs', 'fido');591 doc.subscribe(function(err) {592 if (err) return done(err);593 expect(doc.subscribed).equal(true);594 doc.unsubscribe();595 expect(doc.subscribed).equal(false);596 done();597 });598 });599 it('is set to false sychronously on disconnect', function(done) {600 var doc = this.backend.connect().get('dogs', 'fido');601 doc.subscribe(function(err) {602 if (err) return done(err);603 expect(doc.subscribed).equal(true);604 doc.connection.close();605 expect(doc.subscribed).equal(false);606 done();607 });608 });609 });610});...

Full Screen

Full Screen

metadata.js

Source:metadata.js Github

copy

Full Screen

1/**2 * Copyright (c) 2017-present, Facebook, Inc.3 *4 * This source code is licensed under the MIT license found in the5 * LICENSE file in the root directory of this source tree.6 */7module.exports = {8 'en-doc1': {9 id: 'en-doc1',10 title: 'Document 1',11 source: 'doc1.md',12 version: 'next',13 permalink: 'docs/en/next/doc1.html',14 localized_id: 'doc1',15 language: 'en',16 sidebar: 'docs',17 category: 'Test',18 next_id: 'doc2',19 next: 'en-doc2',20 next_title: 'Document 2',21 sort: 1,22 },23 'en-doc2': {24 id: 'en-doc2',25 title: 'Document 2',26 source: 'doc2.md',27 version: 'next',28 permalink: 'docs/en/next/doc2.html',29 localized_id: 'doc2',30 language: 'en',31 sidebar: 'docs',32 category: 'Test',33 previous_id: 'doc1',34 previous: 'en-doc1',35 previous_title: 'Document 1',36 sort: 2,37 },38 'en-doc3': {39 id: 'en-doc3',40 title: 'Document 3',41 source: 'doc3.md',42 version: 'next',43 permalink: 'docs/en/next/doc3.html',44 localized_id: 'doc3',45 language: 'en',46 sidebar: 'docs',47 category: 'Test 2',48 previous_id: 'doc2',49 previous: 'en-doc2',50 previous_title: 'Document 2',51 sort: 3,52 },53 'en-reflinks': {54 id: 'en-reflinks',55 title: 'Reference Links',56 source: 'reflinks.md',57 version: 'next',58 permalink: 'docs/en/next/reflinks.html',59 localized_id: 'reflinks',60 language: 'en',61 sidebar: 'docs',62 category: 'Test 2',63 previous_id: 'doc3',64 previous: 'en-doc3',65 previous_title: 'Document 3',66 sort: 4,67 },68 'ko-doc1': {69 id: 'ko-doc1',70 title: '문서 1',71 source: 'doc1.md',72 version: 'next',73 permalink: 'docs/ko/next/doc1.html',74 localized_id: 'doc1',75 language: 'ko',76 sidebar: 'docs',77 category: 'Test',78 next_id: 'doc2',79 next: 'ko-doc2',80 next_title: '문서 2',81 },82 'ko-doc2': {83 id: 'ko-doc2',84 title: '문서 2',85 source: 'doc2.md',86 version: 'next',87 permalink: 'docs/ko/next/doc2.html',88 localized_id: 'doc2',89 language: 'ko',90 sidebar: 'docs',91 category: 'Test',92 previous_id: 'doc1',93 previous: 'ko-doc1',94 previous_title: '문서 1',95 },96 'en-version-1.0.0-doc1': {97 id: 'en-version-1.0.0-doc1',98 original_id: 'doc1',99 title: 'Document 1',100 source: 'version-1.0.0/doc1.md',101 version: '1.0.0',102 permalink: 'docs/en/doc1.html',103 localized_id: 'version-1.0.0-doc1',104 language: 'en',105 sidebar: 'version-1.0.0-docs',106 category: 'Test',107 next_id: 'doc2',108 next: 'en-version-1.0.0-doc2',109 next_title: 'Document 2',110 },111 'en-version-1.0.0-doc2': {112 id: 'en-version-1.0.0-doc2',113 original_id: 'doc2',114 title: 'Document 2',115 source: 'version-1.0.0/doc2.md',116 version: '1.0.0',117 permalink: 'docs/en/doc2.html',118 localized_id: 'version-1.0.0-doc2',119 language: 'en',120 sidebar: 'version-1.0.0-docs',121 category: 'Test',122 previous_id: 'doc1',123 previous: 'en-version-1.0.0-doc1',124 previous_title: 'Document 1',125 },126 'ko-version-1.0.0-doc1': {127 id: 'ko-version-1.0.0-doc1',128 title: '문서 1',129 source: 'version-1.0.0/doc1.md',130 version: '1.0.0',131 permalink: 'docs/ko/doc1.html',132 localized_id: 'version-1.0.0-doc1',133 language: 'ko',134 sidebar: 'version-1.0.0-docs',135 category: 'Test',136 next_id: 'doc2',137 next: 'ko-version-1.0.0-doc2',138 next_title: '문서 2',139 },140 'ko-version-1.0.0-doc2': {141 id: 'ko-version-1.0.0-doc2',142 title: '문서 2',143 source: 'version-1.0.0/doc2.md',144 version: '1.0.0',145 permalink: 'docs/ko/doc2.html',146 localized_id: 'version-1.0.0-doc2',147 language: 'ko',148 sidebar: 'version-1.0.0-docs',149 category: 'Test',150 previous_id: 'doc1',151 previous: 'ko-version-1.0.0-doc1',152 previous_title: '문서 1',153 },...

Full Screen

Full Screen

Using AI Code Generation

copy

Full Screen

1var wptools = require('wptools');2var doc2 = wptools.doc2;3var doc2 = new doc2('Albert Einstein');4doc2.get(function(err, data) {5 if (err) {6 console.log(err);7 } else {8 console.log(data);9 }10});11var wptools = require('wptools');12var doc2 = wptools.doc2;13var doc2 = new doc2('Albert Einstein');14doc2.infobox(function(err, data) {15 if (err) {16 console.log(err);17 } else {18 console.log(data);19 }20});21var wptools = require('wptools');22var doc2 = wptools.doc2;23var doc2 = new doc2('Albert Einstein');24doc2.infobox(function(err, data) {25 if (err) {26 console.log(err);27 } else {28 console.log(data);29 }30});31var wptools = require('wptools');32var doc2 = wptools.doc2;33var doc2 = new doc2('Albert Einstein');34doc2.categories(function(err, data) {35 if (err) {36 console.log(err);37 } else {38 console.log(data);39 }40});41var wptools = require('wptools');42var doc2 = wptools.doc2;43var doc2 = new doc2('Albert Einstein');44doc2.coordinates(function(err, data) {45 if (err) {46 console.log(err);47 } else {48 console.log(data);49 }50});

Full Screen

Using AI Code Generation

copy

Full Screen

1var wptools = require('wptools');2wptools.doc2('Albert Einstein').then(function(doc) {3 console.log(doc);4 console.log(doc.infobox('name'));5 console.log(doc.sections('Early life'));6 console.log(doc.categories());7 console.log(doc.links());8 console.log(doc.images());9});10### wptools.page()11wptools.page('Albert Einstein').then(function(page) {12 console.log(page);13});14### wptools.doc()15wptools.doc('Albert Einstein').then(function(doc) {16 console.log(doc);17});18### wptools.doc2()19wptools.doc2('Albert Einstein').then(function(doc) {20 console.log(doc);21});22### wptools.page(title, [options])23### wptools.doc(title, [options])24### wptools.doc2(title, [options])

Full Screen

Using AI Code Generation

copy

Full Screen

1var wptools = require('wptools');2var fs = require('fs');3var path = require('path');4var doc2 = function (page, callback) {5 var page = wptools.page(page);6 page.get(function (err, resp) {7 if (err) {8 console.log(err);9 }10 var data = resp.data;11 var doc2 = data.doc2;12 callback(doc2);13 });14};

Full Screen

Using AI Code Generation

copy

Full Screen

1var wpt = require('./lib/webpagetest.js');2var wpt = new WebPageTest('www.webpagetest.org','A.5c5f5a5c5f5a5c5f5a5c5f5a5c5f5a5');3var location = 'Dulles:Chrome';4var runs = 3;5var pollResults = 5;6var firstViewOnly = false;7var video = true;8var timeline = true;9var netlog = true;10var lighthouse = true;11var lighthouseConfig = {12 settings: {13 }14};15wpt.runTest(url, {16}, function(err, data) {17 if (err) return console.error(err);18 console.log(data);19});

Full Screen

Using AI Code Generation

copy

Full Screen

1var webpagetest = require('webpagetest');2var wpt = new webpagetest('www.webpagetest.org', 'A.2d2f8f1b1a6b9d9e1e9f8e2f2a2b3c3b');3 if (err) return console.error(err);4 console.log('Test status: ' + data.statusText);5 console.log('Test ID: ' + data.data.testId);6 console.log('Test URL: ' + data.data.userUrl);7 console.log('Test results from: ' + data.data.summaryCSV);8 console.log('Test results from: ' + data.data.detailCSV);9});10wpt.getTestStatus('160214_1C_8e6f1a9c9b9d2e2f2a2b3c3b', function(err, data) {11 if (err) return console.error(err);12 console.log('Test status: ' + data.statusText);13 console.log('Test ID: ' + data.data.testId);14 console.log('Test URL: ' + data.data.userUrl);15 console.log('Test results from: ' + data.data.summaryCSV);16 console.log('Test results from: ' + data.data.detailCSV);17});18wpt.getTestResults('160214_1C_8e6f1a9c9b9d2e2f2a2b3c3b', function(err, data) {19 if (err) return console.error(err);20 console.log('Test status: ' + data.statusText);21 console.log('Test ID: ' + data.data.testId);22 console.log('Test URL: ' + data.data.userUrl);23 console.log('Test results from: ' + data.data.summaryCSV);24 console.log('Test results from: ' + data.data.detailCSV);25});26wpt.getLocations(function(err, data) {27 if (err) return console.error(err);28 console.log(data);29});30wpt.getTesters(function(err, data) {31 if (err) return console.error(err);32 console.log(data);33});

Full Screen

Automation Testing Tutorials

Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.

LambdaTest Learning Hubs:

YouTube

You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.

Run wpt automation tests on LambdaTest cloud grid

Perform automation testing on 3000+ real desktop and mobile devices online.

Try LambdaTest Now !!

Get 100 minutes of automation test minutes FREE!!

Next-Gen App & Browser Testing Cloud

Was this article helpful?

Helpful

NotHelpful