Compare commits

..

5 Commits

Author SHA1 Message Date
Kevin Jahns
6b5c02f1ce 13.0.0-16 2017-08-26 01:11:31 +02:00
Kevin Jahns
2be6e935a4 fix lint in xml tests 2017-08-26 01:10:50 +02:00
Kevin Jahns
0ddf3bf742 Y.Xml renamed to Y.XmlElement 2017-08-25 20:35:17 +02:00
Kevin Jahns
5f29724578 merge textarea example 2017-08-24 14:46:16 +02:00
Kevin Jahns
ab6cde07e6 Implemented Xml Struct 2017-08-24 14:44:40 +02:00
26 changed files with 1120 additions and 5665 deletions

1
.gitignore vendored
View File

@@ -1,3 +1,4 @@
node_modules
bower_components
/y.*
/examples/yjs-dist.js*

View File

@@ -0,0 +1,11 @@
<!DOCTYPE html>
<html>
</head>
<!-- jquery is not required for y-xml. It is just here for convenience, and to test batch operations. -->
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<script src="../yjs-dist.js"></script>
<script src="./index.js"></script>
</head>
<body contenteditable="true">
</body>
</html>

View File

@@ -0,0 +1,21 @@
/* global Y */
// initialize a shared object. This function call returns a promise!
Y({
db: {
name: 'memory'
},
connector: {
name: 'websockets-client',
// url: 'http://127.0.0.1:1234',
url: 'http://192.168.178.81:1234',
room: 'html-editor-example6'
},
share: {
xml: 'XmlFragment()' // y.share.xml is of type Y.Xml with tagname "p"
}
}).then(function (y) {
window.yXml = y
// Bind children of XmlFragment to the document.body
window.yXml.share.xml.bindToDom(document.body)
})

View File

@@ -0,0 +1,58 @@
<!DOCTYPE html>
<html>
<body>
<style>
.wrapper {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-gap: 7px;
}
.one {
grid-column: 1 ;
}
.two {
grid-column: 2;
}
.three {
grid-column: 3;
}
textarea {
width: calc(100% - 10px)
}
.editor-container {
background-color: #4caf50;
padding: 4px 5px 10px 5px;
border-radius: 11px;
}
.editor-container[disconnected] {
background-color: red;
}
.disconnected-info {
display: none;
}
.editor-container[disconnected] .disconnected-info {
display: inline;
}
</style>
<div class="wrapper">
<div id="container1" class="one editor-container">
<h1>Server 1 <span class="disconnected-info">(disconnected)</span></h1>
<textarea id="textarea1" rows=40 autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"></textarea>
</div>
<div id="container2" class="two editor-container">
<h1>Server 2 <span class="disconnected-info">(disconnected)</span></h1>
<textarea id="textarea2" rows=40 autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"></textarea>
</div>
<div id="container3" class="three editor-container">
<h1>Server 3 <span class="disconnected-info">(disconnected)</span></h1>
<textarea id="textarea3" rows=40 autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"></textarea>
</div>
</div>
<script src="../../y.js"></script>
<script src="../../../y-array/y-array.js"></script>
<script src="../../../y-text/dist/y-text.js"></script>
<script src="../../../y-memory/y-memory.js"></script>
<script src="../../../y-websockets-client/y-websockets-client.js"></script>
<script src="./index.js"></script>
</body>
</html>

View File

@@ -0,0 +1,64 @@
/* global Y */
Y({
db: {
name: 'memory'
},
connector: {
name: 'websockets-client',
room: 'Textarea-example',
url: 'https://yjs-v13.herokuapp.com/'
},
share: {
textarea: 'Text'
}
}).then(function (y) {
window.y1 = y
y.share.textarea.bind(document.getElementById('textarea1'))
})
Y({
db: {
name: 'memory'
},
connector: {
name: 'websockets-client',
room: 'Textarea-example',
url: 'https://yjs-v13-second.herokuapp.com/'
},
share: {
textarea: 'Text'
}
}).then(function (y) {
window.y2 = y
y.share.textarea.bind(document.getElementById('textarea2'))
y.connector.socket.on('connection', function () {
document.getElementById('container2').removeAttribute('disconnected')
})
y.connector.socket.on('disconnect', function () {
document.getElementById('container2').setAttribute('disconnected', true)
})
})
Y({
db: {
name: 'memory'
},
connector: {
name: 'websockets-client',
room: 'Textarea-example',
url: 'https://yjs-v13-third.herokuapp.com/'
},
share: {
textarea: 'Text'
}
}).then(function (y) {
window.y3 = y
y.share.textarea.bind(document.getElementById('textarea3'))
y.connector.socket.on('connection', function () {
document.getElementById('container3').removeAttribute('disconnected')
})
y.connector.socket.on('disconnect', function () {
document.getElementById('container3').setAttribute('disconnected', true)
})
})

View File

@@ -2,6 +2,10 @@
"name": "examples",
"version": "0.0.0",
"description": "",
"scripts": {
"dist": "rollup -c",
"watch": "rollup -cw"
},
"author": "Kevin Jahns",
"license": "MIT",
"dependencies": {

27
examples/rollup.config.js Normal file
View File

@@ -0,0 +1,27 @@
import nodeResolve from 'rollup-plugin-node-resolve'
import commonjs from 'rollup-plugin-commonjs'
var pkg = require('./package.json')
export default {
entry: 'yjs-dist.esm',
dest: 'yjs-dist.js',
moduleName: 'Y',
format: 'umd',
plugins: [
nodeResolve({
main: true,
module: true,
browser: true
}),
commonjs()
],
sourceMap: true,
banner: `
/**
* ${pkg.name} - ${pkg.description}
* @version v${pkg.version}
* @license ${pkg.license}
*/
`
}

View File

@@ -11,12 +11,12 @@ Y({
connector: {
name: 'websockets-client',
room: 'Textarea-example',
// url: '//localhost:1234',
url: 'https://yjs-v13.herokuapp.com/'
// options: { transports: ['websocket'], upgrade: false }
},
sourceDir: '/bower_components',
share: {
textarea: 'Text', // y.share.textarea is of type Y.Text
test: 'Array'
textarea: 'Text'
},
timeout: 5000 // reject if no connection was established within 5 seconds
}).then(function (y) {

View File

@@ -1,8 +1,9 @@
<!DOCTYPE html>
<html>
</head>
<script src="../bower_components/yjs/y.js"></script>
<script src="../bower_components/jquery/dist/jquery.min.js"></script>
<!-- jquery is not required for y-xml. It is just here for convenience, and to test batch operations. -->
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<script src="../yjs-dist.js"></script>
<script src="./index.js"></script>
</head>
<body>

View File

@@ -7,6 +7,8 @@ Y({
},
connector: {
name: 'websockets-client',
// url: 'http://127.0.0.1:1234',
url: 'http://192.168.178.81:1234',
room: 'Xml-example'
},
sourceDir: '/bower_components',

12
examples/yjs-dist.esm Normal file
View File

@@ -0,0 +1,12 @@
import Y from '../src/y.js'
import yArray from '../../y-array/src/y-array.js'
import yMap from '../../y-map/src/Map.js'
import yText from '../../y-text/src/Text.js'
import yXml from '../../y-xml/src/y-xml.js'
import yMemory from '../../y-memory/src/y-memory.js'
import yWebsocketsClient from '../../y-websockets-client/src/y-websockets-client.js'
Y.extend(yArray, yMap, yText, yXml, yMemory, yWebsocketsClient)
export default Y

2
package-lock.json generated
View File

@@ -1,6 +1,6 @@
{
"name": "yjs",
"version": "13.0.0-13",
"version": "13.0.0-16",
"lockfileVersion": 1,
"dependencies": {
"accepts": {

View File

@@ -1,6 +1,6 @@
{
"name": "yjs",
"version": "13.0.0-15",
"version": "13.0.0-16",
"description": "A framework for real-time p2p shared editing on any data",
"main": "./y.node.js",
"browser": "./y.js",
@@ -10,6 +10,7 @@
"debug": "concurrently 'rollup -wc rollup.test.js' 'cutest-serve y.test.js -o'",
"lint": "standard",
"dist": "rollup -c rollup.browser.js; rollup -c rollup.node.js",
"watch": "concurrently 'rollup -wc rollup.browser.js' 'rollup -wc rollup.node.js'",
"postversion": "npm run dist",
"postpublish": "tag-dist-files --overwrite-existing-tag"
},

View File

@@ -3,7 +3,7 @@ import commonjs from 'rollup-plugin-commonjs'
import multiEntry from 'rollup-plugin-multi-entry'
export default {
entry: 'test/*',
entry: 'test/y-xml.tests.js',
moduleName: 'y-tests',
format: 'umd',
plugins: [

View File

@@ -588,7 +588,7 @@ export default function extendDatabase (Y /* :any */) {
createType (typedefinition, id) {
var structname = typedefinition[0].struct
id = id || this.getNextOpId(1)
var op = Y.Struct[structname].create(id)
var op = Y.Struct[structname].create(id, typedefinition[1])
op.type = typedefinition[0].name
this.requestTransaction(function * () {

File diff suppressed because it is too large Load Diff

View File

@@ -863,7 +863,12 @@ export default function extendTransaction (Y) {
var comp = id[1].split('_')
if (comp.length > 1) {
var struct = comp[0]
var op = Y.Struct[struct].create(id)
let type = Y[comp[1]]
let args = null
if (type != null) {
args = Y.utils.parseTypeDefinition(type, comp[3])
}
var op = Y.Struct[struct].create(id, args)
op.type = comp[1]
yield * this.setOperation(op)
return op

View File

@@ -840,4 +840,17 @@ export default function Utils (Y) {
}
}
Y.utils.generateUserId = generateUserId
Y.utils.parseTypeDefinition = function parseTypeDefinition (type, typeArgs) {
var args = []
try {
args = JSON.parse('[' + typeArgs + ']')
} catch (e) {
throw new Error('Was not able to parse type definition!')
}
if (type.typeDefinition.parseArguments != null) {
args = type.typeDefinition.parseArguments(args[0])[1]
}
return args
}
}

View File

@@ -186,23 +186,15 @@ class YConfig extends Y.utils.NamedEventHandler {
// create shared object
for (var propertyname in opts.share) {
var typeConstructor = opts.share[propertyname].split('(')
let typeArgs = ''
if (typeConstructor.length === 2) {
typeArgs = typeConstructor[1].split(')')[0] || ''
}
var typeName = typeConstructor.splice(0, 1)
var type = Y[typeName]
var typedef = type.typeDefinition
var id = [0xFFFFFF, typedef.struct + '_' + typeName + '_' + propertyname + '_' + typeConstructor]
var args = []
if (typeConstructor.length === 1) {
try {
args = JSON.parse('[' + typeConstructor[0].split(')')[0] + ']')
} catch (e) {
throw new Error('Was not able to parse type definition! (share.' + propertyname + ')')
}
if (type.typeDefinition.parseArguments == null) {
throw new Error(typeName + ' does not expect arguments!')
} else {
args = typedef.parseArguments(args[0])[1]
}
}
var id = [0xFFFFFF, typedef.struct + '_' + typeName + '_' + propertyname + '_' + typeArgs]
let args = Y.utils.parseTypeDefinition(type, typeArgs)
share[propertyname] = yield * this.store.initType.call(this, id, args)
}
})

View File

@@ -163,30 +163,6 @@ test('encode/decode List operations', async function binList (t) {
id: [100, 33],
type: 'Array'
})
t.log('info is an object')
testEncoding(t, writeList, readList, {
struct: 'List',
id: [100, 33],
type: 'Array',
info: { prop: 'yay' }
})
t.log('info is a string')
testEncoding(t, writeList, readList, {
struct: 'List',
id: [100, 33],
type: 'Array',
info: 'hi'
})
t.log('info is a number')
testEncoding(t, writeList, readList, {
struct: 'List',
id: [100, 33],
type: 'Array',
info: 400
})
})
const writeMap = Y.Struct.Map.binaryEncode
@@ -199,31 +175,4 @@ test('encode/decode Map operations', async function binMap (t) {
type: 'Map',
map: {}
})
t.log('info is an object')
testEncoding(t, writeMap, readMap, {
struct: 'Map',
id: [100, 33],
type: 'Map',
info: { prop: 'yay' },
map: {}
})
t.log('info is a string')
testEncoding(t, writeMap, readMap, {
struct: 'Map',
id: [100, 33],
type: 'Map',
map: {},
info: 'hi'
})
t.log('info is a number')
testEncoding(t, writeMap, readMap, {
struct: 'Map',
id: [100, 33],
type: 'Map',
map: {},
info: 400
})
})

288
test/y-xml.tests.js Normal file
View File

@@ -0,0 +1,288 @@
import { wait, initArrays, compareUsers, Y, flushAll, applyRandomTests } from '../../yjs/tests-lib/helper.js'
import { test } from 'cutest'
test('set property', async function xml0 (t) {
var { users, xml0, xml1 } = await initArrays(t, { users: 2 })
xml0.setAttribute('height', 10)
t.assert(xml0.getAttribute('height') === 10, 'Simple set+get works')
await flushAll(t, users)
t.assert(xml1.getAttribute('height') === 10, 'Simple set+get works (remote)')
await compareUsers(t, users)
})
test('events', async function xml1 (t) {
var { users, xml0, xml1 } = await initArrays(t, { users: 2 })
var event
var remoteEvent
let expectedEvent
xml0.observe(function (e) {
delete e._content
delete e.nodes
delete e.values
event = e
})
xml1.observe(function (e) {
delete e._content
delete e.nodes
delete e.values
remoteEvent = e
})
xml0.setAttribute('key', 'value')
expectedEvent = {
type: 'attributeChanged',
value: 'value',
name: 'key'
}
t.compare(event, expectedEvent, 'attribute changed event')
await flushAll(t, users)
t.compare(remoteEvent, expectedEvent, 'attribute changed event (remote)')
// check attributeRemoved
xml0.removeAttribute('key')
expectedEvent = {
type: 'attributeRemoved',
name: 'key'
}
t.compare(event, expectedEvent, 'attribute deleted event')
await flushAll(t, users)
t.compare(remoteEvent, expectedEvent, 'attribute deleted event (remote)')
// test childInserted event
expectedEvent = {
type: 'childInserted',
index: 0
}
xml0.insert(0, [Y.XmlText('some text')])
t.compare(event, expectedEvent, 'child inserted event')
await flushAll(t, users)
t.compare(remoteEvent, expectedEvent, 'child inserted event (remote)')
// test childRemoved
xml0.delete(0)
expectedEvent = {
type: 'childRemoved',
index: 0
}
t.compare(event, expectedEvent, 'child deleted event')
await flushAll(t, users)
t.compare(remoteEvent, expectedEvent, 'child deleted event (remote)')
await compareUsers(t, users)
})
test('attribute modifications (y -> dom)', async function xml2 (t) {
var { users, xml0 } = await initArrays(t, { users: 3 })
let dom0 = xml0.getDom()
xml0.setAttribute('height', '100px')
await wait()
t.assert(dom0.getAttribute('height') === '100px', 'setAttribute')
xml0.removeAttribute('height')
await wait()
t.assert(dom0.getAttribute('height') == null, 'removeAttribute')
xml0.setAttribute('class', 'stuffy stuff')
await wait()
t.assert(dom0.getAttribute('class') === 'stuffy stuff', 'set class attribute')
await compareUsers(t, users)
})
test('attribute modifications (dom -> y)', async function xml3 (t) {
var { users, xml0 } = await initArrays(t, { users: 3 })
let dom0 = xml0.getDom()
dom0.setAttribute('height', '100px')
await wait()
t.assert(xml0.getAttribute('height') === '100px', 'setAttribute')
dom0.removeAttribute('height')
await wait()
t.assert(xml0.getAttribute('height') == null, 'removeAttribute')
dom0.setAttribute('class', 'stuffy stuff')
await wait()
t.assert(xml0.getAttribute('class') === 'stuffy stuff', 'set class attribute')
await compareUsers(t, users)
})
test('element insert (dom -> y)', async function xml4 (t) {
var { users, xml0 } = await initArrays(t, { users: 3 })
let dom0 = xml0.getDom()
dom0.insertBefore(document.createTextNode('some text'), null)
dom0.insertBefore(document.createElement('p'), null)
await wait()
t.assert(xml0.get(0).toString() === 'some text', 'Retrieve Text Node')
t.assert(xml0.get(1).nodeName === 'P', 'Retrieve Element node')
await compareUsers(t, users)
})
test('element insert (y -> dom)', async function xml5 (t) {
var { users, xml0 } = await initArrays(t, { users: 3 })
let dom0 = xml0.getDom()
xml0.insert(0, [Y.XmlText('some text')])
xml0.insert(1, [Y.XmlElement('p')])
t.assert(dom0.childNodes[0].textContent === 'some text', 'Retrieve Text node')
t.assert(dom0.childNodes[1].nodeName === 'P', 'Retrieve Element node')
await compareUsers(t, users)
})
test('y on insert, then delete (dom -> y)', async function xml6 (t) {
var { users, xml0 } = await initArrays(t, { users: 3 })
let dom0 = xml0.getDom()
dom0.insertBefore(document.createElement('p'), null)
await wait()
t.assert(xml0.length === 1, 'one node present')
dom0.childNodes[0].remove()
await wait()
t.assert(xml0.length === 0, 'no node present after delete')
await compareUsers(t, users)
})
test('y on insert, then delete (y -> dom)', async function xml7 (t) {
var { users, xml0 } = await initArrays(t, { users: 3 })
let dom0 = xml0.getDom()
xml0.insert(0, [Y.XmlElement('p')])
t.assert(dom0.childNodes[0].nodeName === 'P', 'Get inserted element from dom')
xml0.delete(0, 1)
t.assert(dom0.childNodes.length === 0, '#childNodes is empty after delete')
await compareUsers(t, users)
})
test('delete consecutive (1) (Text)', async function xml8 (t) {
var { users, xml0 } = await initArrays(t, { users: 3 })
let dom0 = xml0.getDom()
xml0.insert(0, ['1', '2', '3'].map(Y.XmlText))
await wait()
xml0.delete(1, 2)
await wait()
t.assert(xml0.length === 1, 'check length (y)')
t.assert(dom0.childNodes.length === 1, 'check length (dom)')
t.assert(dom0.childNodes[0].textContent === '1', 'check content')
await compareUsers(t, users)
})
test('delete consecutive (2) (Text)', async function xml9 (t) {
var { users, xml0 } = await initArrays(t, { users: 3 })
let dom0 = xml0.getDom()
xml0.insert(0, ['1', '2', '3'].map(Y.XmlText))
await wait()
xml0.delete(0, 1)
xml0.delete(1, 1)
await wait()
t.assert(xml0.length === 1, 'check length (y)')
t.assert(dom0.childNodes.length === 1, 'check length (dom)')
t.assert(dom0.childNodes[0].textContent === '2', 'check content')
await compareUsers(t, users)
})
test('delete consecutive (1) (Element)', async function xml10 (t) {
var { users, xml0 } = await initArrays(t, { users: 3 })
let dom0 = xml0.getDom()
xml0.insert(0, [Y.XmlElement('A'), Y.XmlElement('B'), Y.XmlElement('C')])
await wait()
xml0.delete(1, 2)
await wait()
t.assert(xml0.length === 1, 'check length (y)')
t.assert(dom0.childNodes.length === 1, 'check length (dom)')
t.assert(dom0.childNodes[0].nodeName === 'A', 'check content')
await compareUsers(t, users)
})
test('delete consecutive (2) (Element)', async function xml11 (t) {
var { users, xml0 } = await initArrays(t, { users: 3 })
let dom0 = xml0.getDom()
xml0.insert(0, [Y.XmlElement('A'), Y.XmlElement('B'), Y.XmlElement('C')])
await wait()
xml0.delete(0, 1)
xml0.delete(1, 1)
await wait()
t.assert(xml0.length === 1, 'check length (y)')
t.assert(dom0.childNodes.length === 1, 'check length (dom)')
t.assert(dom0.childNodes[0].nodeName === 'B', 'check content')
await compareUsers(t, users)
})
test('Receive a bunch of elements (with disconnect)', async function xml12 (t) {
var { users, xml0, xml1 } = await initArrays(t, { users: 3 })
let dom0 = xml0.getDom()
let dom1 = xml1.getDom()
users[1].disconnect()
xml0.insert(0, [Y.XmlElement('A'), Y.XmlElement('B'), Y.XmlElement('C')])
xml0.insert(0, [Y.XmlElement('X'), Y.XmlElement('Y'), Y.XmlElement('Z')])
await users[1].reconnect()
await flushAll(t, users)
t.assert(xml0.length === 6, 'check length (y)')
t.assert(xml1.length === 6, 'check length (y) (reconnected user)')
t.assert(dom0.childNodes.length === 6, 'check length (dom)')
t.assert(dom1.childNodes.length === 6, 'check length (dom) (reconnected user)')
await compareUsers(t, users)
})
// TODO: move elements
var xmlTransactions = [
function attributeChange (t, user, chance) {
user.share.xml.getDom().setAttribute(chance.word(), chance.word())
},
function insertText (t, user, chance) {
let dom = user.share.xml.getDom()
var succ = dom.children.length > 0 ? chance.pickone(dom.children) : null
dom.insertBefore(document.createTextNode(chance.word()), succ)
},
function insertDom (t, user, chance) {
let dom = user.share.xml.getDom()
var succ = dom.children.length > 0 ? chance.pickone(dom.children) : null
dom.insertBefore(document.createElement(chance.word()), succ)
},
function deleteChild (t, user, chance) {
let dom = user.share.xml.getDom()
if (dom.childNodes.length > 0) {
var d = chance.pickone(dom.childNodes)
d.remove()
}
},
function insertTextSecondLayer (t, user, chance) {
let dom = user.share.xml.getDom()
if (dom.children.length > 0) {
let dom2 = chance.pickone(dom.children)
let succ = dom2.childNodes.length > 0 ? chance.pickone(dom2.childNodes) : null
dom2.insertBefore(document.createTextNode(chance.word()), succ)
}
},
function insertDomSecondLayer (t, user, chance) {
let dom = user.share.xml.getDom()
if (dom.children.length > 0) {
let dom2 = chance.pickone(dom.children)
let succ = dom2.childNodes.length > 0 ? chance.pickone(dom2.childNodes) : null
dom2.insertBefore(document.createElement(chance.word()), succ)
}
},
function deleteChildSecondLayer (t, user, chance) {
let dom = user.share.xml.getDom()
if (dom.children.length > 0) {
let dom2 = chance.pickone(dom.children)
if (dom2.childNodes.length > 0) {
let d = chance.pickone(dom2.childNodes)
d.remove()
}
}
}
]
test('y-xml: Random tests (10)', async function randomXml10 (t) {
await applyRandomTests(t, xmlTransactions, 10)
})
test('y-xml: Random tests (42)', async function randomXml42 (t) {
await applyRandomTests(t, xmlTransactions, 42)
})
test('y-xml: Random tests (43)', async function randomXml43 (t) {
await applyRandomTests(t, xmlTransactions, 43)
})
test('y-xml: Random tests (44)', async function randomXml44 (t) {
await applyRandomTests(t, xmlTransactions, 44)
})
test('y-xml: Random tests (45)', async function randomXml45 (t) {
await applyRandomTests(t, xmlTransactions, 45)
})
test('y-xml: Random tests (46)', async function randomXml46 (t) {
await applyRandomTests(t, xmlTransactions, 46)
})
test('y-xml: Random tests (47)', async function randomXml47 (t) {
await applyRandomTests(t, xmlTransactions, 47)
})

View File

@@ -3,14 +3,16 @@ import _Y from '../../yjs/src/y.js'
import yMemory from '../../y-memory/src/y-memory.js'
import yArray from '../../y-array/src/y-array.js'
import yText from '../../y-text/src/Text.js'
import yMap from '../../y-map/src/Map.js'
import yXml from '../../y-xml/src/y-xml.js'
import yTest from './test-connector.js'
import Chance from 'chance'
export let Y = _Y
Y.extend(yMemory, yArray, yMap, yTest)
Y.extend(yMemory, yArray, yText, yMap, yTest, yXml)
export var database = { name: 'memory' }
export var connector = { name: 'test', url: 'http://localhost:1234' }
@@ -47,6 +49,31 @@ export async function garbageCollectUsers (t, users) {
await Promise.all(users.map(u => u.db.emptyGarbageCollector()))
}
export function attrsToObject (attrs) {
let obj = {}
for (var i = 0; i < attrs.length; i++) {
let attr = attrs[i]
obj[attr.name] = attr.value
}
return obj
}
export function domToJson (dom) {
if (dom.nodeType === document.TEXT_NODE) {
return dom.textContent
} else if (dom.nodeType === document.ELEMENT_NODE) {
let attributes = attrsToObject(dom.attributes)
let children = Array.from(dom.childNodes.values()).map(domToJson)
return {
name: dom.nodeName,
children: children,
attributes: attributes
}
} else {
throw new Error('Unsupported node type')
}
}
/*
* 1. reconnect and flush all
* 2. user 0 gc
@@ -73,6 +100,7 @@ export async function compareUsers (t, users) {
}
var userMapOneValues = users.map(u => u.share.map.get('one')).map(valueToComparable)
var userMapTwoValues = users.map(u => u.share.map.get('two')).map(valueToComparable)
var userXmlValues = users.map(u => u.share.xml.getDom()).map(domToJson)
await users[0].db.garbageCollect()
await users[0].db.garbageCollect()
@@ -133,6 +161,7 @@ export async function compareUsers (t, users) {
t.compare(userArrayValues[i], userArrayValues[i + 1], 'array types')
t.compare(userMapOneValues[i], userMapOneValues[i + 1], 'map types (propery "one")')
t.compare(userMapTwoValues[i], userMapTwoValues[i + 1], 'map types (propery "two")')
t.compare(userXmlValues[i], userXmlValues[i + 1], 'xml types')
t.compare(data[i].os, data[i + 1].os, 'os')
t.compare(data[i].ds, data[i + 1].ds, 'ds')
t.compare(data[i].ss, data[i + 1].ss, 'ss')
@@ -147,7 +176,7 @@ export async function initArrays (t, opts) {
var result = {
users: []
}
var share = Object.assign({ flushHelper: 'Map', array: 'Array', map: 'Map' }, opts.share)
var share = Object.assign({ flushHelper: 'Map', array: 'Array', map: 'Map', xml: 'XmlElement("div")' }, opts.share)
var chance = opts.chance || new Chance(t.getSeed() * 1000000000)
var conn = Object.assign({ room: 'debugging_' + t.name, generateUserId: false, testContext: t, chance }, connector)
for (let i = 0; i < opts.users; i++) {

10
y.js

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

5062
y.node.js

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long