From 722d39f60885729157ff2dfc571208e231b15317 Mon Sep 17 00:00:00 2001 From: Damien Lebrun Date: Tue, 6 Dec 2016 23:45:03 +0000 Subject: [PATCH 1/6] Simpler rule and data for each database tests --- test/spec/lib/database.js | 620 +++++++++++++++++++++----------------- 1 file changed, 345 insertions(+), 275 deletions(-) diff --git a/test/spec/lib/database.js b/test/spec/lib/database.js index 29955a4..9e0329c 100644 --- a/test/spec/lib/database.js +++ b/test/spec/lib/database.js @@ -13,98 +13,7 @@ const database = require('../../../lib/database'); -function getRuleset() { - - return { - rules: { - '.read': false, - foo: { - '.read': false, - '.write': false, - $bar: { - '.read': 'auth !== null', - '.write': 'auth.id === 1', - baz: { - '.read': 'root.child("users").child($bar).exists()' - } - } - }, - nested: { - $first: { - $second: { - '.read': '$first == $second', - '.write': '$first == $second', - $key: { - '.validate': 'newData.val() == $second' - } - } - } - }, - mixedType: { - $item: { - '.write': true, - '.validate': 'newData.hasChildren(["type", "a"]) || newData.hasChildren(["type", "b"])', - type: { - '.validate': 'newData.val() == "a" || newData.val() == "b"' - }, - a: { - '.validate': 'newData.parent().child("type").val() == "a" \n&& newData.parent().child("b").exists() == false' - }, - b: { - '.validate': 'newData.parent().child("type").val() == "b" \n&& newData.parent().child("a").exists() == false' - } - } - }, - timestamp: { - $foo: { - '.write': true, - '.validate': 'newData.val() == now' - } - } - } - }; - -} - -function getDB() { - - const rules = getRuleset(); - const initialData = { - foo: { - firstChild: { - '.priority': 0, - baz: { - '.value': true - } - }, - secondChild: { - '.priority': 1, - baz: { - '.value': false - } - } - }, - nested: { - one: { - one: {id: {'.value': 'one'}}, - two: {id: {'.value': 'two'}} - } - }, - mixedType: { - first: { - type: {'.value': 'a'}, - a: {'.value': 1} - } - }, - users: { - firstChild: { - '.value': true - } - } - }; - - return database.create(rules, initialData); -} +const TS = Object.freeze({'.sv': 'timestamp'}); describe('database', function() { const _now = Date.now; @@ -435,27 +344,110 @@ describe('database', function() { }); describe('#read', function() { - let db; - before(function() { - db = getDB(); + it('returns the result of attempting to read', function() { + const rules = { + rules: { + foo: { + bar: { + '.read': 'false' + }, + baz: { + '.read': 'true' + } + } + } + }; + const data = null; + const db = database.create(rules, data); + + expect(db.read('foo').allowed).to.be.false(); + expect(db.read('foo/bar').allowed).to.be.false(); + expect(db.read('foo/baz').allowed).to.be.true(); }); - it('returns the result of attempting to read the given path with the given DB state', function() { + it('should propagate variables in path', function() { + const rules = { + rules: { + $a: { + $b: { + '.read': 'false', + $c: { + '.read': '$a != $b && $b != $c' + } + } + } + } + }; + const data = null; + const db = database.create(rules, data); - expect(db.read('foo/firstChild/baz').allowed).to.be.true(); - expect(db.read('foo/secondChild/baz').allowed).to.be.false(); + expect(db.read('foo/foo/foo').allowed).to.be.false(); + expect(db.read('foo/foo/bar').allowed).to.be.false(); + expect(db.read('foo/bar/baz').allowed).to.be.true(); + }); + + it('should have access to data', function() { + const rules = { + rules: { + '.read': 'false', + foo: { + bar: { + '.read': 'data.val() == true' + }, + baz: { + '.read': 'data.val() == true' + }, + fooz: { + '.read': 'root.child("foo/bar").val() == true' + }, + qux: { + '.read': 'root.child("foo/baz").val() == true' + } + } + } + }; + const data = { + foo: { + bar: false, + baz: true + } + }; + const db = database.create(rules, data); + expect(db.read('foo/bar').allowed).to.be.false(); + expect(db.read('foo/baz').allowed).to.be.true(); + expect(db.read('foo/fooz').allowed).to.be.false(); + expect(db.read('foo/qux').allowed).to.be.true(); }); - it('should propagate variables in path', function() { + it('should have access to auth', function() { + const rules = { + rules: { + '.read': 'auth.isAdmin == true', + foo: { + bar: { + '.read': 'auth.isUser == true' + } + } + } + }; + const data = null; + const db = database.create(rules, data); + + const user = {isUser: true}; + const admin = {isAdmin: true}; - expect(db.read('nested/one/two').allowed).to.be.false(); - expect(db.read('nested/one/one').allowed).to.be.true(); + expect(db.as(null).read('foo').allowed).to.be.false(); + expect(db.as(user).read('foo').allowed).to.be.false(); + expect(db.as(admin).read('foo').allowed).to.be.true(); + expect(db.as(null).read('foo/bar').allowed).to.be.false(); + expect(db.as(user).read('foo/bar').allowed).to.be.true(); + expect(db.as(admin).read('foo/bar').allowed).to.be.true(); }); - it('should traverse all read rules', function() { + it('should traverse all read rules while read is denied', function() { const rules = { rules: { '.read': 'false', @@ -470,7 +462,9 @@ describe('database', function() { } } }; - const result = db.with({rules}).read('foo/bar/baz'); + const data = null; + const db = database.create(rules, data); + const result = db.read('foo/bar/baz'); expect(result.logs.map(r => r.path)).to.eql([ '', @@ -495,7 +489,9 @@ describe('database', function() { } } }; - const result = db.with({rules}).read('foo/bar/baz'); + const data = null; + const db = database.create(rules, data); + const result = db.read('foo/bar/baz'); expect(result.logs.map(r => r.path)).to.eql(['', 'foo']); }); @@ -515,7 +511,9 @@ describe('database', function() { } } }; - const result = db.with({rules}).read('foo/bar/baz'); + const data = null; + const db = database.create(rules, data); + const result = db.read('foo/bar/baz'); expect(result.logs.map(r => r.path)).to.eql(['', 'foo/bar/baz']); }); @@ -528,8 +526,8 @@ describe('database', function() { } } }; - - db = database.create(rules, {a: 1}); + const data = {a: 1}; + const db = database.create(rules, data); expect(db.read('/a').allowed).to.be.false(); }); @@ -537,82 +535,132 @@ describe('database', function() { }); describe('#write', function() { - const superAuth = {id: 1}; - let db; - - beforeEach(function() { - db = getDB(); - }); - - it('should match "now" with the server timestamp', function() { - - const newData = {'.sv': 'timestamp'}; - - expect(db.write('timestamp/foo', newData).allowed).to.be.true(); - - }); - - it('returns the result of attempting to write the given path with the given DB state and new data', function() { - const newData = {wut: {'.value': true}}; - - expect(db.write('foo/firstChild', newData).allowed).to.be.false(); - expect(db.as(superAuth).write('foo/firstChild', newData).allowed).to.be.true(); + it('returns the result of attempting to write', function() { + const rules = { + rules: { + foo: { + bar: { + '.write': 'false' + }, + baz: { + '.write': 'true' + } + } + } + }; + const data = null; + const db = database.create(rules, data); + expect(db.write('foo', true).allowed).to.be.false(); + expect(db.write('foo/bar', true).allowed).to.be.false(); + expect(db.write('foo/baz', true).allowed).to.be.true(); }); it('should propagate variables in path', function() { + const rules = { + rules: { + $a: { + $b: { + '.write': 'false', + $c: { + '.write': '$a != $b && $b != $c' + } + } + } + } + }; + const data = null; + const db = database.create(rules, data); - expect(db.write('nested/one/two', {id: 'two'}).allowed).to.be.false(); - expect(db.write('nested/one/one', {id: 'one'}).allowed).to.be.true(); - expect(db.write('nested/one/one', {id: 'two'}).allowed).to.be.false(); - + expect(db.write('foo/foo/foo', true).allowed).to.be.false(); + expect(db.write('foo/foo/bar', true).allowed).to.be.false(); + expect(db.write('foo/bar/baz', true).allowed).to.be.true(); }); it('should prune null keys', function() { - - const value = {a: 1, b: 2}; const rules = {rules: {'.write': true}}; + const data = {a: 1, b: 2}; + const db = database.create(rules, data); - db = database.create(rules, value); - - expect(db.write('/a', null).newRoot.val()).to.be.deep.equal({b: 2}); - expect(db.write('/', {a: 1, b: {}}).newRoot.val()).to.be.deep.equal({a: 1}); - + expect(db.write('/a', null).newRoot.val()).to.deep.equal({b: 2}); + expect(db.write('/', {a: 1, b: {}}).newRoot.val()).to.deep.equal({a: 1}); }); it('should prune null keys deeply', function() { - - const value = {a: {b: 2}}; const rules = {rules: {'.write': true}}; - - db = database.create(rules, value); + const data = {a: {b: 2}}; + const db = database.create(rules, data); const result = db.write('/a/b', null); - expect(result.newRoot.val()).to.be.deep.equal(null); + expect(result.newRoot.val()).to.be.null(); expect(result.newRoot.child('a').val()).to.be.null(); expect(result.newRoot.child('a').exists()).to.be.false(); expect(result.newRoot.val()).to.be.null(); expect(result.newRoot.exists()).to.be.false(); + }); + + it('should match "now" with the server timestamp', function() { + const rules = { + rules: { + '.write': false, + foo: { + '.write': 'newData.val() == now' + } + } + }; + const data = null; + const db = database.create(rules, data); + expect(db.write('foo', 1).allowed).to.be.false(); + expect(db.write('foo', TS).allowed).to.be.true(); }); - it('should replace a node, not merge it', function() { - let result = db.write('mixedType/first', { - type: {'.value': 'b'}, - b: {'.value': 1} - }); + it('should match "now" with the newData server timestamp', function() { + const rules = { + rules: { + '.write': false, + foo: { + '.write': 'newData.val() == now' + } + } + }; + const data = null; + const now = 12345000; + const db = database.create(rules, data); - expect(result.newData.val()).to.eql({type: 'b', b: 1}); - expect(result.allowed).to.be.true(); + expect(db.write('foo', now, null, now).allowed).to.be.true(); + }); - result = db.write('mixedType/first', { - type: {'.value': 'a'}, - b: {'.value': 1} - }); + it('should not match "now" with the data server timestamp', function() { + const rules = { + rules: { + '.write': false, + foo: { + '.write': 'newData.val() == now' + } + } + }; + const data = null; + const now = 12345000; + const db = database.create(rules, data, now); - expect(result.allowed).to.be.false(); + expect(db.write('foo', now).allowed).to.be.false(); + }); + + it('should replace a node, not merge it', function() { + const rules = {rules: {'.write': true}}; + const data = { + foo: { + bar: true, + baz: true + } + }; + const db = database.create(rules, data); + + expect(db.write('foo', null).newData.val()).to.be.null(); + expect(db.write('foo', {qux: true}).newData.val()).to.deep.equal({qux: true}); }); it('should traverse all write rules', function() { @@ -633,12 +681,10 @@ describe('database', function() { } } }; + const data = null; + const db = database.create(rules, data); - db = database.create(rules, null); - - const result = db.write('foo/bar/baz', true); - - expect(result.logs.map(r => r.path)).to.eql([ + expect(db.write('foo/bar/baz', true).logs.map(r => r.path)).to.deep.equal([ '', 'foo', 'foo/bar', @@ -658,12 +704,10 @@ describe('database', function() { } } }; + const data = null; + const db = database.create(rules, data); - db = database.create(rules, null); - - const result = db.write('foo/bar/baz', true); - - expect(result.logs.map(r => r.path)).to.eql(['', 'foo']); + expect(db.write('foo/bar/baz', true).logs.map(r => r.path)).to.eql(['', 'foo']); }); it('should only traverse node with write rules', function() { @@ -681,12 +725,10 @@ describe('database', function() { } } }; + const data = null; + const db = database.create(rules, data); - db = database.create(rules, null); - - const result = db.write('foo/bar/baz', true); - - expect(result.logs.map(r => r.path)).to.eql(['', 'foo/bar/baz']); + expect(db.write('foo/bar/baz', true).logs.map(r => r.path)).to.eql(['', 'foo/bar/baz']); }); it('should traverse/walk all validate rules', function() { @@ -714,9 +756,8 @@ describe('database', function() { } } }; - - db = database.create(rules, null); - + const data = null; + const db = database.create(rules, data); const result = db.write('foo/bar/baz', {d: true, e: {f: true}}); expect(result.logs.filter(r => r.kind === 'validate').map(r => r.path)).to.eql([ @@ -753,9 +794,8 @@ describe('database', function() { } } }; - - db = database.create(rules, null); - + const data = null; + const db = database.create(rules, data); const result = db.write('foo/bar/baz', {d: true, e: {f: true}}); expect(result.logs.filter(r => r.kind === 'validate').map(r => r.path)).to.eql([ @@ -784,9 +824,8 @@ describe('database', function() { } } }; - - db = database.create(rules, null); - + const data = null; + const db = database.create(rules, data); const result = db.write('foo/bar/baz', {d: true}); expect(result.logs.filter(r => r.kind === 'validate').map(r => r.path)).to.eql(['foo/bar/baz/d']); @@ -806,9 +845,8 @@ describe('database', function() { } } }; - - db = database.create(rules, null); - + const data = null; + const db = database.create(rules, data); const result = db.write('foo/bar/baz', null); expect(result.logs.map(r => r.path)).to.eql(['foo']); @@ -822,8 +860,8 @@ describe('database', function() { } } }; - - db = database.create(rules, {a: 1}); + const data = null; + const db = database.create(rules, data); expect(db.write('/a', 2).allowed).to.be.false(); }); @@ -837,8 +875,8 @@ describe('database', function() { } } }; - - db = database.create(rules, {a: 1}); + const data = null; + const db = database.create(rules, data); expect(db.write('/a', 2).allowed).to.be.false(); }); @@ -846,125 +884,159 @@ describe('database', function() { }); describe('#update', function() { - const _now = Date.now; - let db, auth; - beforeEach(function() { - let now = 1000; + it('should allow permitted write', function() { + const rules = { + rules: { + '.write': 'false', + bar: { + '.write': true + }, + $other: { + '.write': false + } + } + }; + const data = null; + const db = database.create(rules, data); - Date.now = () => now++; - }); + const bar = true; + const baz = true; - afterEach(function() { - Date.now = _now; + expect(db.update('/', {bar}).allowed).to.be.true(); + expect(db.update('/', {bar, baz}).allowed).to.be.false(); }); - beforeEach(function() { + it('should allow validated write', function() { const rules = { rules: { - '.read': false, - timestamps: { - $foo: { - '.write': true, - '.validate': 'newData.val() == now' - } - }, - foo: { - '.read': 'auth !== null', - '.write': 'auth.id === 1', - '.validate': 'newData.hasChildren(["bar", "baz", "fooz"])', - bar: { - '.validate': 'data.exists() == false' - } + '.write': 'true', + bar: { + '.validate': true }, - nested: { - $first: { - $second: { - '.write': '$first == $second' - } - } + $other: { + '.validate': false } } }; + const data = null; + const db = database.create(rules, data); - const initialData = { - foo: { - bar: { - '.value': true - }, - baz: { - '.value': true - }, - fooz: { - '.value': true - } - }, - nested: { - one: { - one: { - foo: { - '.value': 1 - } - }, - two: { - foo: { - '.value': 1 - } - } + const bar = true; + const baz = true; + + expect(db.update('/', {bar}).allowed).to.be.true(); + expect(db.update('/', {bar, baz}).allowed).to.be.false(); + }); + + it('should match "now" with the server timestamp', function() { + const rules = { + rules: { + '.write': 'false', + $key: { + '.write': 'newData.val() == now' } } }; + const data = null; + const db = database.create(rules, data); - db = database.create(rules, initialData); + const foo = TS; + const bar = TS; + const baz = 12345000; - auth = {id: 1}; + expect(db.update('/', {foo, bar, baz}).allowed).to.be.false(); + expect(db.update('/', {foo, bar}).allowed).to.be.true(); }); - it('should match "now" with the server timestamp', function() { - const newData = { - 'timestamps/foo': {'.sv': 'timestamp'}, - 'timestamps/bar': {'.sv': 'timestamp'}, - 'timestamps/baz': 12345000 + it('should match "now" with the newData server timestamp', function() { + const rules = { + rules: { + '.write': 'false', + $key: { + '.write': 'newData.val() == now' + } + } }; + const data = null; + const db = database.create(rules, data); - expect(db.update('/', newData).allowed).to.be.false(); - delete newData['timestamps/baz']; + const now = 12345000; + const foo = now; + const bar = now; - expect(db.update('/', newData).allowed).to.be.true(); + expect(db.update('/', {foo, bar}, now).allowed).to.be.true(); }); - it('should allow validate write', function() { - const newData = { - 'foo/baz': false, - 'foo/fooz': false + it('should not match "now" with the data server timestamp', function() { + const rules = { + rules: { + '.write': 'false', + $key: { + '.write': 'newData.val() == now' + } + } }; + const data = null; + const now = 12345000; + const db = database.create(rules, data, now); - expect(db.as(auth).update('/', newData).allowed).to.be.true(); - expect(db.update('/', newData).allowed).to.be.false(); + const foo = now; + const bar = now; - newData['foo/bar'] = false; - expect(db.as(auth).update('/', newData).allowed).to.be.false(); + expect(db.update('/', {foo, bar}).allowed).to.be.false(); }); it('should propagate variables in path', function() { - expect(db.as(auth).update('nested/one/one', {foo: 2}).allowed).to.be.true(); - expect(db.as(auth).update('nested/one/two', {foo: 2}).allowed).to.be.false(); + const rules = { + rules: { + '.write': 'false', + $a: { + $b: { + $c: { + '.write': '$a != $b && $b != $c' + } + } + } + } + }; + const data = null; + const db = database.create(rules, data); + + expect(db.update('/', { + 'foo/foo/baz': true, + 'foo/bar/bar': true + }).allowed).to.be.false(); + + expect(db.update('/', { + 'foo/bar/baz': true, + 'foo/bar/bar': true + }).allowed).to.be.false(); + + expect(db.update('/', { + 'foo/bar/baz': true, + 'foo/bar/qux': true + }).allowed).to.be.true(); }); it('should handle empty patch', function() { - const result = db.as(auth).update('nested/one/one', {}); + const rules = { + rules: { + '.write': 'true' + } + }; + const data = {foo: 1}; + const db = database.create(rules, data); + const result = db.update('/', {}); expect(result.allowed).to.be.true(); expect(result.newData.val()).to.eql({foo: 1}); }); - it('should prune null keys deeply', function() { - + it('should prune null node deeply', function() { const value = {a: {b: 2}}; const rules = {rules: {'.write': true}}; - - db = database.create(rules, value); - + const db = database.create(rules, value); const result = db.update('/', {'/a/b': {}}); expect(result.newRoot.val()).to.be.deep.equal(null); @@ -972,36 +1044,34 @@ describe('database', function() { expect(result.newRoot.child('a').exists()).to.be.false(); expect(result.newRoot.val()).to.be.null(); expect(result.newRoot.exists()).to.be.false(); - }); it('should fail on type error in write rules evaluation', function() { const rules = { rules: { a: { - '.write': 'newData.val().contains("one") === true' + '.write': 'newData.val().contains("one")' } } }; + const data = null; + const db = database.create(rules, data); - db = database.create(rules, {a: 1}); - - expect(db.update('/', {a: 2}).allowed).to.be.false(); + expect(db.update('/', {a: 1}).allowed).to.be.false(); }); it('should fail on error in validate rules evaluation', function() { const rules = { rules: { - '.write': true, a: { - '.validate': 'newData.val().contains("one") === true' + '.validate': 'newData.val().contains("one")' } } }; + const data = null; + const db = database.create(rules, data); - db = database.create(rules, {a: 1}); - - expect(db.update('/', {a: 2}).allowed).to.be.false(); + expect(db.update('/', {a: 1}).allowed).to.be.false(); }); }); From 24cd150d2248e3ec28e2b7c047227db115846add Mon Sep 17 00:00:00 2001 From: Damien Lebrun Date: Wed, 7 Dec 2016 16:35:33 +0000 Subject: [PATCH 2/6] Simpler rule and data for each snapshot tests --- test/spec/lib/database.js | 240 ++++++++++++++++++++------------------ 1 file changed, 127 insertions(+), 113 deletions(-) diff --git a/test/spec/lib/database.js b/test/spec/lib/database.js index 9e0329c..2263c7d 100644 --- a/test/spec/lib/database.js +++ b/test/spec/lib/database.js @@ -41,33 +41,10 @@ describe('database', function() { }); describe('snapshot', function() { - let root; + let rules; beforeEach(function() { - root = database.snapshot('/', { - '.priority': 'hello', - users: { - 'password:c7ec6752-45b3-404f-a2b9-7df07b78d28e': { - '.priority': 1, - name: {'.value': 'Sherlock Holmes'}, - genius: {'.value': true}, - arrests: {'.value': 70} - }, - 'password:500f6e96-92c6-4f60-ad5d-207253aee4d3': { - '.priority': 2, - name: {'.value': 'John Watson'} - }, - 'password:3403291b-fdc9-4995-9a54-9656241c835d': { - '.priority': 0, - name: {'.value': 'Inspector Lestrade'}, - arrests: {'.value': 35} - }, - 'password:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx': { - '.priority': 0, - '.value': null - } - } - }); + rules = {rules: {}}; }); describe('create', function() { @@ -87,23 +64,42 @@ describe('database', function() { describe('#val', function() { it('gets the value at the specified path', function() { - - expect(root.val()).to.deep.equal({ - users: { - 'password:c7ec6752-45b3-404f-a2b9-7df07b78d28e': {name: 'Sherlock Holmes', genius: true, arrests: 70}, - 'password:500f6e96-92c6-4f60-ad5d-207253aee4d3': {name: 'John Watson'}, - 'password:3403291b-fdc9-4995-9a54-9656241c835d': {name: 'Inspector Lestrade', arrests: 35} - } - }); - + const data = { + foo: { + bar: 1, + baz: 2 + }, + qux: 3 + }; + const db = database.create(rules, data); + + expect(db.snapshot('/').val()).to.deep.equal(data); + expect(db.snapshot('/foo').val()).to.deep.equal(data.foo); + expect(db.snapshot('/foo/bar').val()).to.deep.equal(data.foo.bar); + expect(db.snapshot('/foo/baz').val()).to.deep.equal(data.foo.baz); + expect(db.snapshot('/qux').val()).to.deep.equal(data.qux); }); }); describe('#getPriority', function() { - it('gets the priority at the specified path', function() { - expect(root.getPriority()).to.equal('hello'); + it.skip('gets the priority at the specified path', function() { + const data = { + '.priority': 1, + foo: { + bar: { + '.priority': 10, + '.value': 1 + }, + baz: 2 + } + }; + const db = database.create(rules, data); + + expect(db.snapshot('/').getPriority()).to.equal(1); + expect(db.snapshot('/foo/bar').getPriority()).to.equal(10); + expect(db.snapshot('/foo/baz').getPriority()).to.be.null(); }); }); @@ -111,12 +107,16 @@ describe('database', function() { describe('#child', function() { it('gets a new data snapshot for the specified child key', function() { - expect( - root - .child('users/password:500f6e96-92c6-4f60-ad5d-207253aee4d3') - .child('name') - .val() - ).to.equal('John Watson'); + const data = { + foo: { + bar: 1, + baz: 2 + }, + qux: 3 + }; + const snap = database.create(rules, data).snapshot('/'); + + expect(snap.child('foo').val()).to.deep.equal(data.foo); }); }); @@ -124,18 +124,20 @@ describe('database', function() { describe('#parent', function() { it('gets the parent of the snap', function() { + const foo = { + bar: 1, + baz: 2 + }; + const snap = database.create(rules, {foo}).snapshot('/foo'); - expect( - root - .child('users/password:500f6e96-92c6-4f60-ad5d-207253aee4d3/name') - .parent() - .val() - ).to.deep.equal({name: 'John Watson'}); - + expect(snap.parent().val()).to.deep.equal({foo}); }); - it('returns null if we are at the top', function() { - expect(root.parent()).to.be.null(); + it.skip('fail if the snapshot was refering to the data root ', function() { + const data = null; + const snap = database.create(rules, data).snapshot('/'); + + expect(() => snap.parent()).to.throw(); }); }); @@ -143,11 +145,19 @@ describe('database', function() { describe('#exists', function() { it('returns true if some data is at that key', function() { - expect(root.child('users').exists()).to.be.true(); + const data = {foo: 1}; + const snap = database.create(rules, data).snapshot('/'); + + expect(snap.exists()).to.be.true(); + expect(snap.child('foo').exists()).to.be.true(); }); - it('returns false if no data is at that key', function() { - expect(root.child('nonexistent').exists()).to.be.false(); + it('returns true if some data is at that key', function() { + const data = null; + const snap = database.create(rules, data).snapshot('/'); + + expect(snap.exists()).to.be.false(); + expect(snap.child('foo').exists()).to.be.false(); }); }); @@ -155,11 +165,17 @@ describe('database', function() { describe('#hasChild', function() { it('returns true if the path has a child with the given name', function() { - expect(root.hasChild('users')).to.be.true(); + const data = {foo: 1}; + const snap = database.create(rules, data).snapshot('/'); + + expect(snap.hasChild('foo')).to.be.true(); }); it('returns false if the path does not have a child with the given name', function() { - expect(root.hasChild('nonexistent')).to.be.false(); + const data = {foo: 1}; + const snap = database.create(rules, data).snapshot('/'); + + expect(snap.hasChild('bar')).to.be.false(); }); }); @@ -169,19 +185,17 @@ describe('database', function() { describe('with no arguments', function() { it('returns true if the path has any children at all', function() { - expect( - root - .child('users/password:500f6e96-92c6-4f60-ad5d-207253aee4d3') - .hasChildren() - ).to.be.true(); + const data = {foo: 1}; + const snap = database.create(rules, data).snapshot('/'); + + expect(snap.hasChildren()).to.be.true(); }); it('returns false if the path has no children', function() { - expect( - root - .child('users/password:500f6e96-92c6-4f60-ad5d-207253aee4d3/name') - .hasChildren() - ).to.be.false(); + const data = null; + const snap = database.create(rules, data).snapshot('/'); + + expect(snap.hasChildren()).to.be.false(); }); }); @@ -189,7 +203,10 @@ describe('database', function() { describe('with an empty array', function() { it('should should throw', function() { - expect(() => root.hasChildren([])).to.throw(); + const data = {foo: 1}; + const snap = database.create(rules, data).snapshot('/'); + + expect(() => snap.hasChildren([])).to.throw(); }); }); @@ -197,21 +214,17 @@ describe('database', function() { describe('with an array of child names', function() { it('returns true if the path has all the specified children', function() { + const data = {foo: 1, bar: 2}; + const snap = database.create(rules, data).snapshot('/'); - expect( - root - .child('users/password:c7ec6752-45b3-404f-a2b9-7df07b78d28e') - .hasChildren(['name', 'genius', 'arrests']) - ).to.be.true(); - + expect(snap.hasChildren(['foo', 'bar'])).to.be.true(); }); it('returns false if the path is missing even one of the specified children', function() { - expect( - root - .child('users/password:3403291b-fdc9-4995-9a54-9656241c835d') - .hasChildren(['name', 'genius', 'arrests']) - ).to.be.false(); + const data = {foo: 1}; + const snap = database.create(rules, data).snapshot('/'); + + expect(snap.hasChildren(['foo', 'bar'])).to.be.false(); }); }); @@ -221,19 +234,19 @@ describe('database', function() { describe('#isNumber', function() { it('returns true if the value at the path has type number', function() { - expect( - root - .child('users/password:3403291b-fdc9-4995-9a54-9656241c835d/arrests') - .isNumber() - ).to.be.true(); + const data = 1; + const snap = database.create(rules, data).snapshot('/'); + + expect(snap.isNumber()).to.be.true(); }); it('returns false if the value at the path does not have type number', function() { - expect( - root - .child('users/password:500f6e96-92c6-4f60-ad5d-207253aee4d3/arrests') - .isNumber() - ).to.be.false(); + const data = {foo: 'bar', bar: false}; + const db = database.create(rules, data); + + expect(db.snapshot('/').isNumber()).to.be.false(); + expect(db.snapshot('/foo').isNumber()).to.be.false(); + expect(db.snapshot('/bar').isNumber()).to.be.false(); }); }); @@ -241,19 +254,19 @@ describe('database', function() { describe('#isBoolean', function() { it('returns true if the value at the path has type boolean', function() { - expect( - root - .child('users/password:c7ec6752-45b3-404f-a2b9-7df07b78d28e/genius') - .isBoolean() - ).to.be.true(); + const data = false; + const snap = database.create(rules, data).snapshot('/'); + + expect(snap.isBoolean()).to.be.true(); }); it('returns false if the value at the path does not have type boolean', function() { - expect( - root - .child('users/password:3403291b-fdc9-4995-9a54-9656241c835d/name') - .isBoolean() - ).to.be.false(); + const data = {foo: 'bar', bar: 1}; + const db = database.create(rules, data); + + expect(db.snapshot('/').isBoolean()).to.be.false(); + expect(db.snapshot('/foo').isBoolean()).to.be.false(); + expect(db.snapshot('/bar').isBoolean()).to.be.false(); }); }); @@ -261,19 +274,19 @@ describe('database', function() { describe('#isString', function() { it('returns true if the value at the path has type string', function() { - expect( - root - .child('users/password:3403291b-fdc9-4995-9a54-9656241c835d/name') - .isString() - ).to.be.true(); + const data = 'foo'; + const snap = database.create(rules, data).snapshot('/'); + + expect(snap.isString()).to.be.true(); }); it('returns false if the value at the path does not have type string', function() { - expect( - root - .child('users/password:3403291b-fdc9-4995-9a54-9656241c835d') - .isString() - ).to.be.false(); + const data = {foo: 1, bar: true}; + const db = database.create(rules, data); + + expect(db.snapshot('/').isString()).to.be.false(); + expect(db.snapshot('/foo').isString()).to.be.false(); + expect(db.snapshot('/bar').isString()).to.be.false(); }); }); @@ -281,11 +294,12 @@ describe('database', function() { describe('toString', function() { it('should return the snapshot path', function() { - expect( - root - .child('users/password:3403291b-fdc9-4995-9a54-9656241c835d/name') - .toString() - ).to.equal('users/password:3403291b-fdc9-4995-9a54-9656241c835d/name'); + const data = null; + const db = database.create(rules, data); + + expect(db.snapshot('/').toString()).to.equal(''); + expect(db.snapshot('/foo').toString()).to.equal('foo'); + expect(db.snapshot('/foo/bar').toString()).to.equal('foo/bar'); }); }); From 984151ebec1255f18906efbc2bf0902ab66b43d5 Mon Sep 17 00:00:00 2001 From: Damien Lebrun Date: Wed, 7 Dec 2016 17:34:16 +0000 Subject: [PATCH 3/6] Add test for handling of invalid priority values --- test/spec/lib/store.js | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/test/spec/lib/store.js b/test/spec/lib/store.js index 48b79ea..e25fed1 100644 --- a/test/spec/lib/store.js +++ b/test/spec/lib/store.js @@ -115,6 +115,28 @@ describe('store', function() { expect(data.b.c.d.$priority()).to.equal(priority); }); + it('should return the node priority set with explicite priority', function() { + const value = 3; + + data = store.create(); + + expect(data.$set('foo', value).foo.$priority()).to.undefined(); + expect(data.$set('foo', value, 1).foo.$priority()).to.equal(1); + expect(data.$set('foo', value, 'something').foo.$priority()).to.equal('something'); + }); + + it.skip('should throw when setting invalid priority', function() { + expect(() => store.create({'.value': 1, '.priority': {foo: 'bar'}})).to.throw(); + expect(() => store.create({'.value': 1, '.priority': true})).to.throw(); + + const value = 3; + + data = store.create(); + + expect(() => data.$set('foo', value, true)).to.throw(); + expect(() => data.$set('foo', value, {foo: 'bar'})).to.throw(); + }); + it('should return the node priority set with explicite priority', function() { data = store.create().$set('a', 3, priority); From ceae4e240b8c84a456de79eeaf562af72580de92 Mon Sep 17 00:00:00 2001 From: Damien Lebrun Date: Thu, 8 Dec 2016 12:41:59 +0000 Subject: [PATCH 4/6] Add inspect command --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 1a4d264..607a28e 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,8 @@ "format": "npm run lint -- --fix", "lint": "eslint lib/ plugins/ test/ bin/targaryen", "lint:html": "(npm run -s lint -- --max-warnings 0 -f html -o lint.html && rm lint.html) || echo 'open lint.html for linting errors'", - "test": "mocha -r test/setup.js test/spec/ --recursive && jasmine && node ./bin/targaryen --verbose test/integration/rules.json test/integration/tests.json" + "test": "mocha -r test/setup.js test/spec/ --recursive && jasmine && node ./bin/targaryen --verbose test/integration/rules.json test/integration/tests.json", + "test:inspect": "node --inspect --debug-brk node_modules/.bin/_mocha -r test/setup.js test/spec/ --recursive" }, "author": "Harry Schmidt ", "license": "ISC", From 1bd07791971a0ffa57199981d04f59ec0b2d2830 Mon Sep 17 00:00:00 2001 From: Damien Lebrun Date: Thu, 8 Dec 2016 14:13:35 +0000 Subject: [PATCH 5/6] Simpler plugins integration test --- test/jasmine/core.js | 208 ++++++++++++---------------------- test/spec/plugins/chai.js | 230 +++++++++++++------------------------- 2 files changed, 150 insertions(+), 288 deletions(-) diff --git a/test/jasmine/core.js b/test/jasmine/core.js index 2588cea..6f71879 100644 --- a/test/jasmine/core.js +++ b/test/jasmine/core.js @@ -5,164 +5,102 @@ 'use strict'; const targaryen = require('../../plugins/jasmine'); +const util = require('../../lib/util'); describe('the targaryen Jasmine plugin', function() { beforeEach(function() { jasmine.addMatchers(targaryen.matchers); + util.resetFirebase(); }); - describe('if not configured correctly', function() { - - it('errors on any expectation', function() { - - expect(function() { - expect(null).canRead('foo'); - }).toThrow(); - - expect(function() { - expect(null).cannotRead('foo'); - }).toThrow(); - - expect(function() { - expect(null).canWrite('foo', 7); - }).toThrow(); - - expect(function() { - expect(null).cannotWrite('foo', 7); - }).toThrow(); - - }); + it('should throw if rules are not set', function() { + targaryen.setFirebaseData(null); + expect(() => expect(null).canRead('foo')).toThrow(); + expect(() => expect(null).cannotRead('foo')).toThrow(); + expect(() => expect(null).canWrite('foo', 7)).toThrow(); + expect(() => expect(null).cannotWrite('foo', 7)).toThrow(); }); - describe('if configured correctly', function() { + it('should throw if data is not set', function() { + targaryen.setFirebaseRules({rules: {'.read': true, '.write': true}}); - beforeEach(function() { + expect(() => expect(null).canRead('foo')).toThrow(); + expect(() => expect(null).canWrite('foo', 7)).toThrow(); - targaryen.setFirebaseData({ - users: { - 'password:500f6e96-92c6-4f60-ad5d-207253aee4d3': { - name: 'Sherlock Holmes' - }, - 'password:3403291b-fdc9-4995-9a54-9656241c835d': { - name: 'John Watson' - } + targaryen.setFirebaseRules({rules: {'.read': false, '.write': false}}); - } - }); + expect(() => expect(null).cannotRead('foo')).toThrow(); + expect(() => expect(null).cannotWrite('foo', 7)).toThrow(); + }); - targaryen.setFirebaseRules({ - rules: { - users: { - $user: { - '.read': 'auth !== null', - '.write': 'auth.uid === $user' - } - }, - posts: { - $post: { - '.read': true, - '.write': 'newData.child("author").val() == auth.uid' - } - } + it('should test read access', function() { + targaryen.setFirebaseData(null); + targaryen.setFirebaseRules({rules: { + '.read': false, + foo: { + bar: { + '.read': 'auth.uid !== null' } - }); + } + }}); - }); - - it('runs tests against the provided data and rules', function() { - - expect(targaryen.users.password).canRead('users/password:500f6e96-92c6-4f60-ad5d-207253aee4d3'); - expect(targaryen.users.unauthenticated).canRead('posts/first'); - expect(targaryen.users.unauthenticated).cannotRead('users/password:500f6e96-92c6-4f60-ad5d-207253aee4d3'); - - expect(targaryen.users.password) - .canWrite('users/password:500f6e96-92c6-4f60-ad5d-207253aee4d3', {name: 'Sherlock Holmes, Ph.D'}); - expect(targaryen.users.password) - .cannotWrite('posts/newpost', {author: 'password:3403291b-fdc9-4995-9a54-9656241c835d'}); - - }); + expect(targaryen.users.unauthenticated).cannotRead('/'); + expect(targaryen.users.unauthenticated).cannotRead('/foo'); + expect(targaryen.users.unauthenticated).cannotRead('/foo/bar'); + expect(targaryen.users.facebook).cannotRead('/'); + expect(targaryen.users.facebook).cannotRead('/foo'); + expect(targaryen.users.facebook).canRead('/foo/bar'); }); - describe('deep write', function() { - beforeEach(function() { - targaryen.setFirebaseData( - {flats: {'221bbakerst': {landlady: 'Mrs Hudson'}}} - ); - targaryen.setFirebaseRules({ - rules: { - flats: { - $cid: { - '.validate': 'newData.hasChildren([\'landlady\'])', - '.write': 'true', - '.read': 'true' - } - } + it('should test write access', function() { + targaryen.setFirebaseData(null); + targaryen.setFirebaseRules({rules: { + '.write': false, + foo: { + bar: { + '.write': 'auth.uid !== null', + '.validate': 'newData.val() > 1' } - }); - }); - it('should not check parent validations', function() { - expect({uid: 'holmes'}).canWrite('/flats/221bbakerst/tenants/Holmes', {}); - }); + } + }}); + + expect(targaryen.users.unauthenticated).cannotWrite('/', 2); + expect(targaryen.users.unauthenticated).cannotWrite('/foo', 2); + expect(targaryen.users.unauthenticated).cannotWrite('/foo/bar', 1); + expect(targaryen.users.unauthenticated).cannotWrite('/foo/bar', 2); + + expect(targaryen.users.facebook).cannotWrite('/', 2); + expect(targaryen.users.facebook).cannotWrite('/foo', 2); + expect(targaryen.users.facebook).cannotWrite('/foo/bar', 1); + expect(targaryen.users.facebook).canWrite('/foo/bar', 2); }); - describe('canPatch', function() { - beforeEach(function() { - targaryen.setFirebaseData({ - users: { - 'some-provider:1': { - name: 'Sherlock Holmes' - }, - 'some-provider:2': { - name: 'John Watson' - } - }, - posts: { - somePost: { - author: 'some-provider:1', - created: Date.now(), - text: 'Hello!' - } + it('should test multi write access', function() { + targaryen.setFirebaseData(null); + targaryen.setFirebaseRules({rules: { + '.write': false, + foo: { + $key: { + '.write': 'auth.uid !== null', + '.validate': 'newData.val() > 1' } - }); - - targaryen.setFirebaseRules({ - rules: { - users: { - $user: { - '.read': 'auth.uid === $user', - '.write': 'auth.isSuper === true' - } - }, - posts: { - $post: { - '.read': true, - '.write': true, - '.validate': 'newData.hasChildren(["created", "text", "author"]) && newData.child("author").val() === auth.uid', - created: { - '.validate': 'data.exists() == false' - }, - author: { - '.validate': 'data.exists() == false' - } - } - } - } - }); - }); - it('should test a patch operation is allowed', function() { - expect({uid: 'some-provider:1'}).canPatch('/posts/somePost', { - text: 'Hello World!' - }); - }); - it('should test a patch operation is not allowed', function() { - expect({uid: 'some-provider:1'}).cannotPatch('/posts/somePost', { - text: 'Hello World!', - created: Date.now() - }); - }); + } + }}); + + expect(targaryen.users.unauthenticated).cannotPatch('/', {foo: {bar: 2, baz: 2}}); + expect(targaryen.users.unauthenticated).cannotPatch('/', {'foo/bar': 1, 'foo/baz': 2}); + expect(targaryen.users.unauthenticated).cannotPatch('/', {'foo/bar': 2, 'foo/baz': 2}); + expect(targaryen.users.unauthenticated).cannotPatch('/foo', {bar: 1, baz: 2}); + expect(targaryen.users.unauthenticated).cannotPatch('/foo', {bar: 2, baz: 2}); + + expect(targaryen.users.facebook).cannotPatch('/', {foo: {bar: 2, baz: 2}}); + expect(targaryen.users.facebook).cannotPatch('/', {'foo/bar': 1, 'foo/baz': 2}); + expect(targaryen.users.facebook).canPatch('/', {'foo/bar': 2, 'foo/baz': 2}); + expect(targaryen.users.facebook).cannotPatch('/foo', {bar: 1, baz: 2}); + expect(targaryen.users.facebook).canPatch('/foo', {bar: 2, baz: 2}); }); describe('using nested variables in path', function() { diff --git a/test/spec/plugins/chai.js b/test/spec/plugins/chai.js index 5f7d0ec..5bc7bcd 100644 --- a/test/spec/plugins/chai.js +++ b/test/spec/plugins/chai.js @@ -6,6 +6,7 @@ const chai = require('chai'); const targaryen = require('../../../plugins/chai'); +const util = require('../../../lib/util'); describe('Chai plugin', function() { @@ -13,175 +14,98 @@ describe('Chai plugin', function() { chai.use(targaryen); }); - describe('if unconfigured', function() { - - it('throws an error for any test', function() { - - expect(function() { - expect(null).can.read.path('/'); - }).to.throw(); + beforeEach(function() { + util.resetFirebase(); + util.setVerbose(true); + }); - }); + it('should throw if rules are not set', function() { + targaryen.setFirebaseData(null); + expect(() => expect(null).can.read.path('foo')).to.throw(); + expect(() => expect(null).cannot.read.path('foo')).to.throw(); + expect(() => expect(null).can.write(7).to.path('foo')).to.throw(); + expect(() => expect(null).cannot.write(7).to.path('foo')).to.throw(); }); - describe('#setFirebaseData', function() { + it('should throw if data is not set', function() { + targaryen.setFirebaseRules({rules: {'.read': true, '.write': true}}); - it('sets the underlying Firebase database to the supplied data', function() { + expect(() => expect(null).can.read.path('foo')).to.throw(); + expect(() => expect(null).can.write(7).to.path('foo')).to.throw(); - targaryen.setFirebaseData({ - users: { - 'password:500f6e96-92c6-4f60-ad5d-207253aee4d3': { - name: 'Sherlock Holmes' - }, - 'password:3403291b-fdc9-4995-9a54-9656241c835d': { - name: 'John Watson' - } - } - }); - - }); + targaryen.setFirebaseRules({rules: {'.read': false, '.write': false}}); + expect(() => expect(null).cannot.read.path('foo')).to.throw(); + expect(() => expect(null).cannot.write(7).to.path('foo')).to.throw(); }); - describe('#setFirebaseRules', function() { - - it('sets the underlying Firebase database to the supplied data', function() { - - targaryen.setFirebaseRules({ - rules: { - users: { - $user: { - '.read': 'auth.uid === $user', - '.write': 'auth.isSuper === true' - } - }, - posts: { - $post: { - '.read': true, - '.write': true, - '.validate': 'newData.hasChildren(["created", "text", "author"]) && newData.child("author").val() === auth.uid', - created: { - '.validate': 'data.exists() == false' - }, - author: { - '.validate': 'data.exists() == false' - } - } - } + it('should test read access', function() { + targaryen.setFirebaseData(null); + targaryen.setFirebaseRules({rules: { + '.read': false, + foo: { + bar: { + '.read': 'auth.uid !== null' } - }); + } + }}); - }); + expect(targaryen.users.unauthenticated).cannot.read.path('/'); + expect(targaryen.users.unauthenticated).cannot.read.path('/foo'); + expect(targaryen.users.unauthenticated).cannot.read.path('/foo/bar'); + expect(targaryen.users.facebook).cannot.read.path('/'); + expect(targaryen.users.facebook).cannot.read.path('/foo'); + expect(targaryen.users.facebook).can.read.path('/foo/bar'); }); - describe('when properly configured', function() { - - beforeEach(function() { - - targaryen.setFirebaseData({ - users: { - 'password:500f6e96-92c6-4f60-ad5d-207253aee4d3': { - name: 'Sherlock Holmes' - }, - 'password:3403291b-fdc9-4995-9a54-9656241c835d': { - name: 'John Watson' - } + it('should test write access', function() { + targaryen.setFirebaseData(null); + targaryen.setFirebaseRules({rules: { + '.write': false, + foo: { + bar: { + '.write': 'auth.uid !== null', + '.validate': 'newData.val() > 1' } - }); - - targaryen.setFirebaseRules({ - rules: { - users: { - $user: { - '.read': 'auth.uid === $user', - '.write': 'auth.isSuper === true' - } - }, - posts: { - $post: { - '.read': true, - '.write': true, - '.validate': 'newData.hasChildren(["created", "text", "author"]) && newData.child("author").val() === auth.uid', - created: { - '.validate': 'data.exists() == false' - }, - author: { - '.validate': 'data.exists() == false' - } - } - } - } - }); - }); - - it('permits read tests', function() { - expect(null).cannot.read.path('users/password:500f6e96-92c6-4f60-ad5d-207253aee4d3'); - expect({uid: 'password:500f6e96-92c6-4f60-ad5d-207253aee4d3'}).can.read.path('users/password:500f6e96-92c6-4f60-ad5d-207253aee4d3'); - }); - - it('permits write tests', function() { - - expect({uid: 'password:500f6e96-92c6-4f60-ad5d-207253aee4d3'}).cannot.write({smart: true}) - .to.path('users/password:500f6e96-92c6-4f60-ad5d-207253aee4d3'); - - expect({uid: 'password:500f6e96-92c6-4f60-ad5d-207253aee4d3', isSuper: true}).can.write({stupid: true}) - .to.path('users/password:500f6e96-92c6-4f60-ad5d-207253aee4d3'); - - expect({uid: 'password:500f6e96-92c6-4f60-ad5d-207253aee4d3'}).cannot.write({ - author: 'password:3403291b-fdc9-4995-9a54-9656241c835d', - created: Date.now(), - text: 'Hello!' - }) - .to.path('posts/newpost'); - - expect({uid: 'password:500f6e96-92c6-4f60-ad5d-207253aee4d3'}).cannot.write({ - author: 'password:500f6e96-92c6-4f60-ad5d-207253aee4d3' - }) - .to.path('posts/newpost'); - - expect({uid: 'password:500f6e96-92c6-4f60-ad5d-207253aee4d3'}).can.write({ - author: 'password:500f6e96-92c6-4f60-ad5d-207253aee4d3', - created: Date.now(), - text: 'Hello!' - }) - .to.path('posts/newpost'); - - }); - - it('should permit patch tests', function() { - targaryen.setFirebaseData({ - users: { - 'password:500f6e96-92c6-4f60-ad5d-207253aee4d3': { - name: 'Sherlock Holmes' - }, - 'password:3403291b-fdc9-4995-9a54-9656241c835d': { - name: 'John Watson' - } - }, - posts: { - somePost: { - author: 'password:500f6e96-92c6-4f60-ad5d-207253aee4d3', - created: Date.now(), - text: 'Hello!' - } - } - }); - - expect({uid: 'password:500f6e96-92c6-4f60-ad5d-207253aee4d3'}).can.patch({ - text: 'Hello World!' - }) - .to.path('posts/somePost'); - - expect({uid: 'password:500f6e96-92c6-4f60-ad5d-207253aee4d3'}).cannot.patch({ - text: 'Hello World!', - created: Date.now() - }) - .to.path('posts/somePost'); - - }); + } + }}); + + expect(targaryen.users.unauthenticated).cannot.write(2).to.path('/'); + expect(targaryen.users.unauthenticated).cannot.write(2).to.path('/foo'); + expect(targaryen.users.unauthenticated).cannot.write(1).to.path('/foo/bar'); + expect(targaryen.users.unauthenticated).cannot.write(2).to.path('/foo/bar'); + + expect(targaryen.users.facebook).cannot.write(2).to.path('/'); + expect(targaryen.users.facebook).cannot.write(2).to.path('/foo'); + expect(targaryen.users.facebook).cannot.write(1).to.path('/foo/bar'); + expect(targaryen.users.facebook).can.write(2).to.path('/foo/bar'); + }); + it('should test multi write access', function() { + targaryen.setFirebaseData(null); + targaryen.setFirebaseRules({rules: { + '.write': false, + foo: { + $key: { + '.write': 'auth.uid !== null', + '.validate': 'newData.val() > 1' + } + } + }}); + + expect(targaryen.users.unauthenticated).cannot.patch({foo: {bar: 2, baz: 2}}).path('/'); + expect(targaryen.users.unauthenticated).cannot.patch({'foo/bar': 1, 'foo/baz': 2}).path('/'); + expect(targaryen.users.unauthenticated).cannot.patch({'foo/bar': 2, 'foo/baz': 2}).path('/'); + expect(targaryen.users.unauthenticated).cannot.patch({bar: 1, baz: 2}).path('/foo'); + expect(targaryen.users.unauthenticated).cannot.patch({bar: 2, baz: 2}).path('/foo'); + + expect(targaryen.users.facebook).cannot.patch({foo: {bar: 2, baz: 2}}).path('/'); + expect(targaryen.users.facebook).cannot.patch({'foo/bar': 1, 'foo/baz': 2}).path('/'); + expect(targaryen.users.facebook).can.patch({'foo/bar': 2, 'foo/baz': 2}).path('/'); + expect(targaryen.users.facebook).cannot.patch({bar: 1, baz: 2}).path('/foo'); + expect(targaryen.users.facebook).can.patch({bar: 2, baz: 2}).path('/foo'); }); }); From a72dddfbcb3b3bfc0610d9ff4f4dcdbff3517581 Mon Sep 17 00:00:00 2001 From: Damien Lebrun Date: Thu, 8 Dec 2016 15:25:02 +0000 Subject: [PATCH 6/6] Remove redundant tests The plugin tests on test the test framework interface with targaryen. Tests regarding targaryen behaviour should not be define there. --- test/jasmine/core.js | 151 ------------------------------------------- 1 file changed, 151 deletions(-) diff --git a/test/jasmine/core.js b/test/jasmine/core.js index 6f71879..4aa226f 100644 --- a/test/jasmine/core.js +++ b/test/jasmine/core.js @@ -103,155 +103,4 @@ describe('the targaryen Jasmine plugin', function() { expect(targaryen.users.facebook).canPatch('/foo', {bar: 2, baz: 2}); }); - describe('using nested variables in path', function() { - - beforeEach(function() { - // using double quotes to make the data & rules compatible with Firebase (web interface) - - targaryen.setFirebaseData({ - users: { - password: { - 'password:500f6e96-92c6-4f60-ad5d-207253aee4d3': { - name: 'Sherlock Holmes' - }, - 'password:3403291b-fdc9-4995-9a54-9656241c835d': { - name: 'John Watson' - } - } - }, - first: { - second: { - third: { - any: 'value' - } - } - } - }); - - targaryen.setFirebaseRules({ - rules: { - users: { - $provider: { - $user: { - // all data is personal (read and write) - '.read': 'auth !== null && auth.uid === $user && auth.provider === $provider', - '.write': 'auth !== null && auth.uid === $user && auth.provider === $provider' - } - } - }, - posts: { - $post: { - '.read': true, - '.write': 'newData.child(\'author\').val() == auth.uid' - } - }, - $one: { - $two: { - $three: { - '.read': '$one == \'first\' && $two == \'second\' && $three == \'third\'' - } - } - } - } - }); - - }); - - it('should allow read based on auth uid and provider', function() { - expect(targaryen.users.password).canRead('users/password/password:500f6e96-92c6-4f60-ad5d-207253aee4d3'); - }); - - it('should allow read based on 3 path segment names', function() { - expect(targaryen.users.unauthenticated).canRead('first/second/third'); - }); - - }); - - describe('delete nodes', function() { - beforeEach(function() { - targaryen.setFirebaseData({ - test: { - number: 42, - bool: true - }, - canDelete: 'test', - otherCanDelete: 'test' - }); - targaryen.setFirebaseRules({ - rules: { - test: { - '.write': 'true', - '.read': 'true', - '.validate': 'newData.hasChildren([\'number\', \'bool\'])', - number: { - '.validate': 'newData.isNumber()' - }, - bool: { - '.validate': 'newData.isBoolean()' - } - }, - canDelete: { - '.read': 'true', - '.write': 'true', - '.validate': 'newData.isString()' - }, - shouldValidate: { - '.read': 'true', - '.write': 'true', - '.validate': 'newData.isBoolean()' - }, - otherCanDelete: { - '.read': 'true', - '.write': 'true', - '.validate': 'newData.isString()' - } - } - }); - }); - - it('should not be able to delete /test/number', function() { - expect({uid: 'anyone'}).cannotWrite('test/number', null); - }); - - it('should be able to delete /test', function() { - expect({uid: 'anyone'}).canWrite('test', null); - }); - - it('should be able to delete /canDelete', function() { - expect({uid: 'anyone'}).canWrite('canDelete', null); - }); - - it('should not be able to delete part of /test in a multi-update', function() { - expect({uid: 'anyone'}).cannotPatch('/', { - 'test/bool': null, - canDelete: null - }); - }); - - it('should be able to delete as part of a multi-path write', function() { - expect({uid: 'anyone'}).canPatch('/', { - test: { - bool: false, - number: 5 - }, - canDelete: null - }); - }); - - it('should be able to delete a whole object by nulling all children', function() { - expect({uid: 'anyone'}).canWrite('test', { - bool: null, - number: null - }); - }); - - it('should not be able to write invalid data by deleting a sibling', function() { - expect({uid: 'anyone'}).cannotWrite('/', { - canDelete: null, - shouldValidate: 'not a boolean', - otherCanDelete: null - }); - }); - - }); });